Bug Summary

File:home/maarten/src/libreoffice/core/extensions/source/scanner/grid.cxx
Warning:line 670, column 40
The left operand of '-' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name grid.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/extensions/inc -I /home/maarten/src/libreoffice/core/external/sane/inc -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/extensions/source/scanner/grid.cxx

/home/maarten/src/libreoffice/core/extensions/source/scanner/grid.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21#include <osl/thread.h>
22#include <cstdio>
23#include <math.h>
24#include <boost/math/special_functions/expm1.hpp>
25
26#include <bitmaps.hlst>
27#include <cmath>
28
29#include "grid.hxx"
30#include <vcl/bitmapex.hxx>
31#include <vcl/customweld.hxx>
32#include <vcl/event.hxx>
33#include <vcl/settings.hxx>
34#include <vcl/svapp.hxx>
35
36#include <algorithm>
37#include <limits>
38#include <memory>
39
40class GridWindow : public weld::CustomWidgetController
41{
42 // helper class for handles
43 struct impHandle
44 {
45 Point maPos;
46 sal_uInt16 mnOffX;
47 sal_uInt16 mnOffY;
48
49 impHandle(const Point& rPos, sal_uInt16 nX, sal_uInt16 nY)
50 : maPos(rPos), mnOffX(nX), mnOffY(nY)
51 {
52 }
53
54 bool operator<(const impHandle& rComp) const
55 {
56 return (maPos.X() < rComp.maPos.X());
57 }
58
59 void draw(vcl::RenderContext& rRenderContext, const BitmapEx& rBitmapEx)
60 {
61 const Point aOffset(rRenderContext.PixelToLogic(Point(mnOffX, mnOffY)));
62 rRenderContext.DrawBitmapEx(maPos - aOffset, rBitmapEx);
63 }
64
65 bool isHit(OutputDevice const & rWin, const Point& rPos)
66 {
67 const Point aOffset(rWin.PixelToLogic(Point(mnOffX, mnOffY)));
68 const tools::Rectangle aTarget(maPos - aOffset, maPos + aOffset);
69 return aTarget.IsInside(rPos);
70 }
71 };
72
73 tools::Rectangle m_aGridArea;
74
75 double m_fMinX;
76 double m_fMinY;
77 double m_fMaxX;
78 double m_fMaxY;
79
80 double m_fChunkX;
81 double m_fMinChunkX;
82 double m_fChunkY;
83 double m_fMinChunkY;
84
85 double* m_pXValues;
86 double* m_pOrigYValues;
87 int m_nValues;
88 std::unique_ptr<double[]> m_pNewYValues;
89
90 sal_uInt16 m_BmOffX;
91 sal_uInt16 m_BmOffY;
92
93 bool m_bCutValues;
94
95 // stuff for handles
96 using Handles = std::vector<impHandle>;
97 static constexpr auto npos = std::numeric_limits<Handles::size_type>::max();
98 Handles m_aHandles;
99 Handles::size_type m_nDragIndex;
100
101 BitmapEx m_aMarkerBitmap;
102
103 Point transform( double x, double y );
104 void transform( const Point& rOriginal, double& x, double& y );
105
106 double findMinX();
107 double findMinY();
108 double findMaxX();
109 double findMaxY();
110
111 void drawGrid(vcl::RenderContext& rRenderContext);
112 void drawOriginal(vcl::RenderContext& rRenderContext);
113 void drawNew(vcl::RenderContext& rRenderContext);
114 void drawHandles(vcl::RenderContext& rRenderContext);
115
116 void computeExtremes();
117 static void computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut );
118 void computeNew();
119 static double interpolate( double x, double const * pNodeX, double const * pNodeY, int nNodes );
120
121 virtual bool MouseMove( const MouseEvent& ) override;
122 virtual bool MouseButtonDown( const MouseEvent& ) override;
123 virtual bool MouseButtonUp( const MouseEvent& ) override;
124 void onResize();
125 virtual void Resize() override;
126 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
127 void drawLine(vcl::RenderContext& rRenderContext, double x1, double y1, double x2, double y2);
128public:
129 GridWindow();
130 void Init(double* pXValues, double* pYValues, int nValues, bool bCutValues, const BitmapEx &rMarkerBitmap);
131 virtual ~GridWindow() override;
132
133 void setBoundings( double fMinX, double fMinY, double fMaxX, double fMaxY );
134
135 double* getNewYValues() { return m_pNewYValues.get(); }
136
137 void ChangeMode(ResetType nType);
138
139 virtual void Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect ) override;
140};
141
142GridWindow::GridWindow()
143 : m_aGridArea(50, 15, 100, 100)
144 , m_fMinX(0.0)
145 , m_fMinY(0.0)
146 , m_fMaxX(0.0)
147 , m_fMaxY(0.0)
148 , m_fChunkX(0.0)
149 , m_fMinChunkX(0.0)
150 , m_fChunkY(0.0)
151 , m_fMinChunkY(0.0)
152 , m_pXValues(nullptr)
153 , m_pOrigYValues(nullptr)
154 , m_nValues(0)
155 , m_BmOffX(0)
156 , m_BmOffY(0)
157 , m_bCutValues(false)
158 , m_aHandles()
159 , m_nDragIndex(npos)
160{
161}
162
163void GridWindow::Init(double* pXValues, double* pYValues, int nValues, bool bCutValues, const BitmapEx &rMarkerBitmap)
164{
165 m_aMarkerBitmap = rMarkerBitmap;
166 m_pXValues = pXValues;
167 m_pOrigYValues = pYValues;
168 m_nValues = nValues;
169 m_bCutValues = bCutValues;
170
171 onResize();
172
173 if (m_pOrigYValues && m_nValues)
174 {
175 m_pNewYValues.reset(new double[ m_nValues ]);
176 memcpy( m_pNewYValues.get(), m_pOrigYValues, sizeof( double ) * m_nValues );
177 }
178
179 setBoundings( 0, 0, 1023, 1023 );
180 computeExtremes();
181
182 // create left and right marker as first and last entry
183 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
184 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
185 m_aHandles.push_back(impHandle(transform(findMinX(), findMinY()), m_BmOffX, m_BmOffY));
186 m_aHandles.push_back(impHandle(transform(findMaxX(), findMaxY()), m_BmOffX, m_BmOffY));
187}
188
189void GridWindow::Resize()
190{
191 onResize();
192}
193
194void GridWindow::onResize()
195{
196 Size aSize = GetOutputSizePixel();
197 m_aGridArea.setWidth( aSize.Width() - 80 );
198 m_aGridArea.setHeight( aSize.Height() - 40 );
199}
200
201void GridWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
202{
203 Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(240, 200), MapMode(MapUnit::MapAppFont)));
204 pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
205 CustomWidgetController::SetDrawingArea(pDrawingArea);
206 SetOutputSizePixel(aSize);
207}
208
209GridDialog::GridDialog(weld::Window* pParent, double* pXValues, double* pYValues, int nValues)
210 : GenericDialogController(pParent, "modules/scanner/ui/griddialog.ui", "GridDialog")
211 , m_xOKButton(m_xBuilder->weld_button("ok"))
212 , m_xResetTypeBox(m_xBuilder->weld_combo_box("resetTypeCombobox"))
213 , m_xResetButton(m_xBuilder->weld_button("resetButton"))
214 , m_xGridWindow(new GridWindow)
215 , m_xGridWindowWND(new weld::CustomWeld(*m_xBuilder, "gridwindow", *m_xGridWindow))
216{
217 m_xGridWindow->Init(pXValues, pYValues, nValues, true/*bCutValues*/, BitmapEx(RID_SCANNER_HANDLE"extensions/res/scanner/handle.png"));
218 m_xResetTypeBox->set_active(0);
219 m_xResetButton->connect_clicked( LINK( this, GridDialog, ClickButtonHdl )::tools::detail::makeLink( ::tools::detail::castTo<GridDialog
*>(this), &GridDialog::LinkStubClickButtonHdl)
);
220}
221
222GridDialog::~GridDialog()
223{
224}
225
226GridWindow::~GridWindow()
227{
228 m_pNewYValues.reset();
229}
230
231double GridWindow::findMinX()
232{
233 if( ! m_pXValues )
234 return 0.0;
235 double fMin = m_pXValues[0];
236 for( int i = 1; i < m_nValues; i++ )
237 if( m_pXValues[ i ] < fMin )
238 fMin = m_pXValues[ i ];
239 return fMin;
240}
241
242double GridWindow::findMinY()
243{
244 if( ! m_pNewYValues )
245 return 0.0;
246 double fMin = m_pNewYValues[0];
247 for( int i = 1; i < m_nValues; i++ )
248 if( m_pNewYValues[ i ] < fMin )
249 fMin = m_pNewYValues[ i ];
250 return fMin;
251}
252
253
254double GridWindow::findMaxX()
255{
256 if( ! m_pXValues )
257 return 0.0;
258 double fMax = m_pXValues[0];
259 for( int i = 1; i < m_nValues; i++ )
260 if( m_pXValues[ i ] > fMax )
261 fMax = m_pXValues[ i ];
262 return fMax;
263}
264
265
266double GridWindow::findMaxY()
267{
268 if( ! m_pNewYValues )
269 return 0.0;
270 double fMax = m_pNewYValues[0];
271 for( int i = 1; i < m_nValues; i++ )
272 if( m_pNewYValues[ i ] > fMax )
273 fMax = m_pNewYValues[ i ];
274 return fMax;
275}
276
277
278void GridWindow::computeExtremes()
279{
280 if( !(m_nValues && m_pXValues && m_pOrigYValues) )
281 return;
282
283 m_fMaxX = m_fMinX = m_pXValues[0];
284 m_fMaxY = m_fMinY = m_pOrigYValues[0];
285 for( int i = 1; i < m_nValues; i++ )
286 {
287 if( m_pXValues[ i ] > m_fMaxX )
288 m_fMaxX = m_pXValues[ i ];
289 else if( m_pXValues[ i ] < m_fMinX )
290 m_fMinX = m_pXValues[ i ];
291 if( m_pOrigYValues[ i ] > m_fMaxY )
292 m_fMaxY = m_pOrigYValues[ i ];
293 else if( m_pOrigYValues[ i ] < m_fMinY )
294 m_fMinY = m_pOrigYValues[ i ];
295 }
296 setBoundings( m_fMinX, m_fMinY, m_fMaxX, m_fMaxY );
297}
298
299
300Point GridWindow::transform( double x, double y )
301{
302 Point aRet;
303
304 aRet.setX( static_cast<long>( ( x - m_fMinX ) *
305 static_cast<double>(m_aGridArea.GetWidth()) / ( m_fMaxX - m_fMinX )
306 + m_aGridArea.Left() ) );
307 aRet.setY( static_cast<long>(
308 m_aGridArea.Bottom() -
309 ( y - m_fMinY ) *
310 static_cast<double>(m_aGridArea.GetHeight()) / ( m_fMaxY - m_fMinY ) ) );
311 return aRet;
312}
313
314void GridWindow::transform( const Point& rOriginal, double& x, double& y )
315{
316 const long nWidth = m_aGridArea.GetWidth();
317 const long nHeight = m_aGridArea.GetHeight();
318 if (!nWidth
15.1
'nWidth' is 0
15.1
'nWidth' is 0
|| !nHeight)
319 return;
16
Returning without writing to 'x'
320 x = ( rOriginal.X() - m_aGridArea.Left() ) * (m_fMaxX - m_fMinX) / static_cast<double>(nWidth) + m_fMinX;
321 y = ( m_aGridArea.Bottom() - rOriginal.Y() ) * (m_fMaxY - m_fMinY) / static_cast<double>(nHeight) + m_fMinY;
322}
323
324void GridWindow::drawLine(vcl::RenderContext& rRenderContext, double x1, double y1, double x2, double y2 )
325{
326 rRenderContext.DrawLine(transform(x1, y1), transform(x2, y2));
327}
328
329void GridWindow::computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut )
330{
331 // get a nice chunk size like 10, 100, 25 or such
332 fChunkOut = ( fMax - fMin ) / 6.0;
333 int logchunk = static_cast<int>(std::log10( fChunkOut ));
334 int nChunk = static_cast<int>( fChunkOut / std::exp( static_cast<double>(logchunk-1) * M_LN102.30258509299404568402 ) );
335 if( nChunk >= 75 )
336 nChunk = 100;
337 else if( nChunk >= 35 )
338 nChunk = 50;
339 else if ( nChunk > 20 )
340 nChunk = 25;
341 else if ( nChunk >= 13 )
342 nChunk = 20;
343 else if( nChunk > 5 )
344 nChunk = 10;
345 else
346 nChunk = 5;
347 fChunkOut = static_cast<double>(nChunk) * exp( static_cast<double>(logchunk-1) * M_LN102.30258509299404568402 );
348 // compute whole chunks fitting into fMin
349 nChunk = static_cast<int>( fMin / fChunkOut );
350 fMinChunkOut = static_cast<double>(nChunk) * fChunkOut;
351 while( fMinChunkOut < fMin )
352 fMinChunkOut += fChunkOut;
353}
354
355
356void GridWindow::computeNew()
357{
358 if(2 == m_aHandles.size())
359 {
360 // special case: only left and right markers
361 double xleft, yleft;
362 double xright, yright;
363 transform(m_aHandles[0].maPos, xleft, yleft);
364 transform(m_aHandles[1].maPos, xright, yright );
365 double factor = (yright-yleft)/(xright-xleft);
366 for( int i = 0; i < m_nValues; i++ )
367 {
368 m_pNewYValues[ i ] = yleft + ( m_pXValues[ i ] - xleft )*factor;
369 }
370 }
371 else
372 {
373 // sort markers
374 std::sort(m_aHandles.begin(), m_aHandles.end());
375 const int nSorted = m_aHandles.size();
376 int i;
377
378 // get node arrays
379 std::unique_ptr<double[]> nodex(new double[ nSorted ]);
380 std::unique_ptr<double[]> nodey(new double[ nSorted ]);
381
382 for( i = 0; i < nSorted; i++ )
383 transform( m_aHandles[i].maPos, nodex[ i ], nodey[ i ] );
384
385 for( i = 0; i < m_nValues; i++ )
386 {
387 double x = m_pXValues[ i ];
388 m_pNewYValues[ i ] = interpolate( x, nodex.get(), nodey.get(), nSorted );
389 if( m_bCutValues )
390 {
391 if( m_pNewYValues[ i ] > m_fMaxY )
392 m_pNewYValues[ i ] = m_fMaxY;
393 else if( m_pNewYValues[ i ] < m_fMinY )
394 m_pNewYValues[ i ] = m_fMinY;
395 }
396 }
397 }
398}
399
400
401double GridWindow::interpolate(
402 double x,
403 double const * pNodeX,
404 double const * pNodeY,
405 int nNodes )
406{
407 // compute Lagrange interpolation
408 double ret = 0;
409 for( int i = 0; i < nNodes; i++ )
410 {
411 double sum = pNodeY[ i ];
412 for( int n = 0; n < nNodes; n++ )
413 {
414 if( n != i )
415 {
416 sum *= x - pNodeX[ n ];
417 sum /= pNodeX[ i ] - pNodeX[ n ];
418 }
419 }
420 ret += sum;
421 }
422 return ret;
423}
424
425void GridDialog::setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY)
426{
427 m_xGridWindow->setBoundings(fMinX, fMinY, fMaxX, fMaxY);
428}
429
430void GridWindow::setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY)
431{
432 m_fMinX = fMinX;
433 m_fMinY = fMinY;
434 m_fMaxX = fMaxX;
435 m_fMaxY = fMaxY;
436
437 computeChunk( m_fMinX, m_fMaxX, m_fChunkX, m_fMinChunkX );
438 computeChunk( m_fMinY, m_fMaxY, m_fChunkY, m_fMinChunkY );
439}
440
441void GridWindow::drawGrid(vcl::RenderContext& rRenderContext)
442{
443 char pBuf[256];
444 rRenderContext.SetLineColor(COL_BLACK);
445 // draw vertical lines
446 for (double fX = m_fMinChunkX; fX < m_fMaxX; fX += m_fChunkX)
447 {
448 drawLine(rRenderContext, fX, m_fMinY, fX, m_fMaxY);
449 // draw tickmarks
450 Point aPt = transform(fX, m_fMinY);
451 std::sprintf(pBuf, "%g", fX);
452 OUString aMark(pBuf, strlen(pBuf), osl_getThreadTextEncoding());
453 Size aTextSize(rRenderContext.GetTextWidth(aMark), rRenderContext.GetTextHeight());
454 aPt.AdjustX( -(aTextSize.Width() / 2) );
455 aPt.AdjustY(aTextSize.Height() / 2 );
456 rRenderContext.DrawText(aPt, aMark);
457 }
458 // draw horizontal lines
459 for (double fY = m_fMinChunkY; fY < m_fMaxY; fY += m_fChunkY)
460 {
461 drawLine(rRenderContext, m_fMinX, fY, m_fMaxX, fY);
462 // draw tickmarks
463 Point aPt = transform(m_fMinX, fY);
464 std::sprintf(pBuf, "%g", fY);
465 OUString aMark(pBuf, strlen(pBuf), osl_getThreadTextEncoding());
466 Size aTextSize(rRenderContext.GetTextWidth(aMark), rRenderContext.GetTextHeight());
467 aPt.AdjustX( -(aTextSize.Width() + 2) );
468 aPt.AdjustY( -(aTextSize.Height() / 2) );
469 rRenderContext.DrawText(aPt, aMark);
470 }
471
472 // draw boundings
473 drawLine(rRenderContext, m_fMinX, m_fMinY, m_fMaxX, m_fMinY);
474 drawLine(rRenderContext, m_fMinX, m_fMaxY, m_fMaxX, m_fMaxY);
475 drawLine(rRenderContext, m_fMinX, m_fMinY, m_fMinX, m_fMaxY);
476 drawLine(rRenderContext, m_fMaxX, m_fMinY, m_fMaxX, m_fMaxY);
477}
478
479void GridWindow::drawOriginal(vcl::RenderContext& rRenderContext)
480{
481 if (m_nValues && m_pXValues && m_pOrigYValues)
482 {
483 rRenderContext.SetLineColor(COL_RED);
484 for (int i = 0; i < m_nValues - 1; i++)
485 {
486 drawLine(rRenderContext,
487 m_pXValues[i], m_pOrigYValues[i],
488 m_pXValues[i + 1], m_pOrigYValues[i + 1]);
489 }
490 }
491}
492
493void GridWindow::drawNew(vcl::RenderContext& rRenderContext)
494{
495 if (m_nValues && m_pXValues && m_pNewYValues)
496 {
497 rRenderContext.SetClipRegion(vcl::Region(m_aGridArea));
498 rRenderContext.SetLineColor(COL_YELLOW);
499 for (int i = 0; i < m_nValues - 1; i++)
500 {
501 drawLine(rRenderContext,
502 m_pXValues[i], m_pNewYValues[i],
503 m_pXValues[i + 1], m_pNewYValues[i + 1]);
504 }
505 rRenderContext.SetClipRegion();
506 }
507}
508
509void GridWindow::drawHandles(vcl::RenderContext& rRenderContext)
510{
511 for(impHandle & rHandle : m_aHandles)
512 {
513 rHandle.draw(rRenderContext, m_aMarkerBitmap);
514 }
515}
516
517void GridWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
518{
519 rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor()));
520 drawGrid(rRenderContext);
521 drawOriginal(rRenderContext);
522 drawNew(rRenderContext);
523 drawHandles(rRenderContext);
524}
525
526bool GridWindow::MouseMove( const MouseEvent& rEvt )
527{
528 if( rEvt.GetButtons() == MOUSE_LEFT(sal_uInt16(0x0001)) && m_nDragIndex != npos )
529 {
530 Point aPoint( rEvt.GetPosPixel() );
531
532 if( m_nDragIndex == 0 || m_nDragIndex == m_aHandles.size() - 1)
533 {
534 aPoint.setX( m_aHandles[m_nDragIndex].maPos.X() );
535 }
536 else
537 {
538 if(aPoint.X() < m_aGridArea.Left())
539 aPoint.setX( m_aGridArea.Left() );
540 else if(aPoint.X() > m_aGridArea.Right())
541 aPoint.setX( m_aGridArea.Right() );
542 }
543
544 if( aPoint.Y() < m_aGridArea.Top() )
545 aPoint.setY( m_aGridArea.Top() );
546 else if( aPoint.Y() > m_aGridArea.Bottom() )
547 aPoint.setY( m_aGridArea.Bottom() );
548
549 if( aPoint != m_aHandles[m_nDragIndex].maPos )
550 {
551 m_aHandles[m_nDragIndex].maPos = aPoint;
552 Invalidate( m_aGridArea );
553 }
554 }
555
556 return false;
557}
558
559bool GridWindow::MouseButtonUp( const MouseEvent& rEvt )
560{
561 if( rEvt.GetButtons() == MOUSE_LEFT(sal_uInt16(0x0001)) )
562 {
563 if( m_nDragIndex != npos )
564 {
565 m_nDragIndex = npos;
566 computeNew();
567 Invalidate(m_aGridArea);
568 }
569 }
570
571 return false;
572}
573
574bool GridWindow::MouseButtonDown( const MouseEvent& rEvt )
575{
576 Point aPoint( rEvt.GetPosPixel() );
577 Handles::size_type nMarkerIndex = npos;
578
579 for(Handles::size_type a(0); nMarkerIndex == npos && a < m_aHandles.size(); a++)
580 {
581 if(m_aHandles[a].isHit(GetDrawingArea()->get_ref_device(), aPoint))
582 {
583 nMarkerIndex = a;
584 }
585 }
586
587 if( rEvt.GetButtons() == MOUSE_LEFT(sal_uInt16(0x0001)) )
588 {
589 // user wants to drag a button
590 if( nMarkerIndex != npos )
591 {
592 m_nDragIndex = nMarkerIndex;
593 }
594 }
595 else if( rEvt.GetButtons() == MOUSE_RIGHT(sal_uInt16(0x0004)) )
596 {
597 // user wants to add/delete a button
598 if( nMarkerIndex != npos )
599 {
600 if( nMarkerIndex != 0 && nMarkerIndex != m_aHandles.size() - 1)
601 {
602 // delete marker under mouse
603 if( m_nDragIndex == nMarkerIndex )
604 m_nDragIndex = npos;
605
606 m_aHandles.erase(m_aHandles.begin() + nMarkerIndex);
607 }
608 }
609 else
610 {
611 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
612 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
613 m_aHandles.push_back(impHandle(aPoint, m_BmOffX, m_BmOffY));
614 }
615
616 computeNew();
617 Invalidate(m_aGridArea);
618 }
619
620 return false;
621}
622
623void GridWindow::ChangeMode(ResetType nType)
624{
625 switch( nType )
3
Control jumps to 'case RESET:' at line 643
626 {
627 case ResetType::LINEAR_ASCENDING:
628 {
629 for( int i = 0; i < m_nValues; i++ )
630 {
631 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
632 }
633 }
634 break;
635 case ResetType::LINEAR_DESCENDING:
636 {
637 for( int i = 0; i < m_nValues; i++ )
638 {
639 m_pNewYValues[ i ] = m_fMaxY - (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
640 }
641 }
642 break;
643 case ResetType::RESET:
644 {
645 if( m_pOrigYValues && m_pNewYValues && m_nValues )
4
Assuming field 'm_pOrigYValues' is null
646 memcpy( m_pNewYValues.get(), m_pOrigYValues, m_nValues*sizeof(double) );
647 }
648 break;
5
Execution continues on line 662
649 case ResetType::EXPONENTIAL:
650 {
651 for( int i = 0; i < m_nValues; i++ )
652 {
653 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)*(boost::math::expm1((m_pXValues[i]-m_fMinX)/(m_fMaxX-m_fMinX)))/(M_E2.7182818284590452354-1.0);
654 }
655 }
656 break;
657
658 default:
659 break;
660 }
661
662 if (m_pNewYValues)
6
Calling 'unique_ptr::operator bool'
10
Returning from 'unique_ptr::operator bool'
11
Taking true branch
663 {
664 for(size_t i(0); i < m_aHandles.size(); i++)
12
Assuming the condition is true
13
Loop condition is true. Entering loop body
665 {
666 // find nearest xvalue
667 double x, y;
14
'x' declared without an initial value
668 transform( m_aHandles[i].maPos, x, y );
15
Calling 'GridWindow::transform'
17
Returning from 'GridWindow::transform'
669 int nIndex = 0;
670 double delta = std::fabs( x-m_pXValues[0] );
18
The left operand of '-' is a garbage value
671 for( int n = 1; n < m_nValues; n++ )
672 {
673 if( delta > std::fabs( x - m_pXValues[ n ] ) )
674 {
675 delta = std::fabs( x - m_pXValues[ n ] );
676 nIndex = n;
677 }
678 }
679 if( 0 == i )
680 m_aHandles[i].maPos = transform( m_fMinX, m_pNewYValues[ nIndex ] );
681 else if( m_aHandles.size() - 1 == i )
682 m_aHandles[i].maPos = transform( m_fMaxX, m_pNewYValues[ nIndex ] );
683 else
684 m_aHandles[i].maPos = transform( m_pXValues[ nIndex ], m_pNewYValues[ nIndex ] );
685 }
686 }
687
688 Invalidate();
689}
690
691IMPL_LINK_NOARG(GridDialog, ClickButtonHdl, weld::Button&, void)void GridDialog::LinkStubClickButtonHdl(void * instance, weld
::Button& data) { return static_cast<GridDialog *>(
instance)->ClickButtonHdl(data); } void GridDialog::ClickButtonHdl
(__attribute__ ((unused)) weld::Button&)
1
Calling 'GridDialog::ClickButtonHdl'
692{
693 int nType = m_xResetTypeBox->get_active();
694 m_xGridWindow->ChangeMode(static_cast<ResetType>(nType));
2
Calling 'GridWindow::ChangeMode'
695}
696
697double* GridDialog::getNewYValues()
698{
699 return m_xGridWindow->getNewYValues();
700}
701
702/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/bits/unique_ptr.h

1// unique_ptr implementation -*- C++ -*-
2
3// Copyright (C) 2008-2020 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/unique_ptr.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{memory}
28 */
29
30#ifndef _UNIQUE_PTR_H1
31#define _UNIQUE_PTR_H1 1
32
33#include <bits/c++config.h>
34#include <debug/assertions.h>
35#include <type_traits>
36#include <utility>
37#include <tuple>
38#include <bits/stl_function.h>
39#include <bits/functional_hash.h>
40#if __cplusplus201703L > 201703L
41# include <compare>
42# include <ostream>
43#endif
44
45namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
46{
47_GLIBCXX_BEGIN_NAMESPACE_VERSION
48
49 /**
50 * @addtogroup pointer_abstractions
51 * @{
52 */
53
54#if _GLIBCXX_USE_DEPRECATED1
55#pragma GCC diagnostic push
56#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
57 template<typename> class auto_ptr;
58#pragma GCC diagnostic pop
59#endif
60
61 /// Primary template of default_delete, used by unique_ptr for single objects
62 template<typename _Tp>
63 struct default_delete
64 {
65 /// Default constructor
66 constexpr default_delete() noexcept = default;
67
68 /** @brief Converting constructor.
69 *
70 * Allows conversion from a deleter for objects of another type, `_Up`,
71 * only if `_Up*` is convertible to `_Tp*`.
72 */
73 template<typename _Up,
74 typename = _Require<is_convertible<_Up*, _Tp*>>>
75 default_delete(const default_delete<_Up>&) noexcept { }
76
77 /// Calls `delete __ptr`
78 void
79 operator()(_Tp* __ptr) const
80 {
81 static_assert(!is_void<_Tp>::value,
82 "can't delete pointer to incomplete type");
83 static_assert(sizeof(_Tp)>0,
84 "can't delete pointer to incomplete type");
85 delete __ptr;
86 }
87 };
88
89 // _GLIBCXX_RESOLVE_LIB_DEFECTS
90 // DR 740 - omit specialization for array objects with a compile time length
91
92 /// Specialization of default_delete for arrays, used by `unique_ptr<T[]>`
93 template<typename _Tp>
94 struct default_delete<_Tp[]>
95 {
96 public:
97 /// Default constructor
98 constexpr default_delete() noexcept = default;
99
100 /** @brief Converting constructor.
101 *
102 * Allows conversion from a deleter for arrays of another type, such as
103 * a const-qualified version of `_Tp`.
104 *
105 * Conversions from types derived from `_Tp` are not allowed because
106 * it is undefined to `delete[]` an array of derived types through a
107 * pointer to the base type.
108 */
109 template<typename _Up,
110 typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>>
111 default_delete(const default_delete<_Up[]>&) noexcept { }
112
113 /// Calls `delete[] __ptr`
114 template<typename _Up>
115 typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type
116 operator()(_Up* __ptr) const
117 {
118 static_assert(sizeof(_Tp)>0,
119 "can't delete pointer to incomplete type");
120 delete [] __ptr;
121 }
122 };
123
124 /// @cond undocumented
125
126 // Manages the pointer and deleter of a unique_ptr
127 template <typename _Tp, typename _Dp>
128 class __uniq_ptr_impl
129 {
130 template <typename _Up, typename _Ep, typename = void>
131 struct _Ptr
132 {
133 using type = _Up*;
134 };
135
136 template <typename _Up, typename _Ep>
137 struct
138 _Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>>
139 {
140 using type = typename remove_reference<_Ep>::type::pointer;
141 };
142
143 public:
144 using _DeleterConstraint = enable_if<
145 __and_<__not_<is_pointer<_Dp>>,
146 is_default_constructible<_Dp>>::value>;
147
148 using pointer = typename _Ptr<_Tp, _Dp>::type;
149
150 static_assert( !is_rvalue_reference<_Dp>::value,
151 "unique_ptr's deleter type must be a function object type"
152 " or an lvalue reference type" );
153
154 __uniq_ptr_impl() = default;
155 __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
156
157 template<typename _Del>
158 __uniq_ptr_impl(pointer __p, _Del&& __d)
159 : _M_t(__p, std::forward<_Del>(__d)) { }
160
161 __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept
162 : _M_t(std::move(__u._M_t))
163 { __u._M_ptr() = nullptr; }
164
165 __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept
166 {
167 reset(__u.release());
168 _M_deleter() = std::forward<_Dp>(__u._M_deleter());
169 return *this;
170 }
171
172 pointer& _M_ptr() { return std::get<0>(_M_t); }
173 pointer _M_ptr() const { return std::get<0>(_M_t); }
174 _Dp& _M_deleter() { return std::get<1>(_M_t); }
175 const _Dp& _M_deleter() const { return std::get<1>(_M_t); }
176
177 void reset(pointer __p) noexcept
178 {
179 const pointer __old_p = _M_ptr();
180 _M_ptr() = __p;
181 if (__old_p)
182 _M_deleter()(__old_p);
183 }
184
185 pointer release() noexcept
186 {
187 pointer __p = _M_ptr();
188 _M_ptr() = nullptr;
189 return __p;
190 }
191
192 void
193 swap(__uniq_ptr_impl& __rhs) noexcept
194 {
195 using std::swap;
196 swap(this->_M_ptr(), __rhs._M_ptr());
197 swap(this->_M_deleter(), __rhs._M_deleter());
198 }
199
200 private:
201 tuple<pointer, _Dp> _M_t;
202 };
203
204 // Defines move construction + assignment as either defaulted or deleted.
205 template <typename _Tp, typename _Dp,
206 bool = is_move_constructible<_Dp>::value,
207 bool = is_move_assignable<_Dp>::value>
208 struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp>
209 {
210 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
211 __uniq_ptr_data(__uniq_ptr_data&&) = default;
212 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
213 };
214
215 template <typename _Tp, typename _Dp>
216 struct __uniq_ptr_data<_Tp, _Dp, true, false> : __uniq_ptr_impl<_Tp, _Dp>
217 {
218 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
219 __uniq_ptr_data(__uniq_ptr_data&&) = default;
220 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
221 };
222
223 template <typename _Tp, typename _Dp>
224 struct __uniq_ptr_data<_Tp, _Dp, false, true> : __uniq_ptr_impl<_Tp, _Dp>
225 {
226 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
227 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
228 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
229 };
230
231 template <typename _Tp, typename _Dp>
232 struct __uniq_ptr_data<_Tp, _Dp, false, false> : __uniq_ptr_impl<_Tp, _Dp>
233 {
234 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
235 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
236 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
237 };
238 /// @endcond
239
240 /// 20.7.1.2 unique_ptr for single objects.
241 template <typename _Tp, typename _Dp = default_delete<_Tp>>
242 class unique_ptr
243 {
244 template <typename _Up>
245 using _DeleterConstraint =
246 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
247
248 __uniq_ptr_data<_Tp, _Dp> _M_t;
249
250 public:
251 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
252 using element_type = _Tp;
253 using deleter_type = _Dp;
254
255 private:
256 // helper template for detecting a safe conversion from another
257 // unique_ptr
258 template<typename _Up, typename _Ep>
259 using __safe_conversion_up = __and_<
260 is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,
261 __not_<is_array<_Up>>
262 >;
263
264 public:
265 // Constructors.
266
267 /// Default constructor, creates a unique_ptr that owns nothing.
268 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
269 constexpr unique_ptr() noexcept
270 : _M_t()
271 { }
272
273 /** Takes ownership of a pointer.
274 *
275 * @param __p A pointer to an object of @c element_type
276 *
277 * The deleter will be value-initialized.
278 */
279 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
280 explicit
281 unique_ptr(pointer __p) noexcept
282 : _M_t(__p)
283 { }
284
285 /** Takes ownership of a pointer.
286 *
287 * @param __p A pointer to an object of @c element_type
288 * @param __d A reference to a deleter.
289 *
290 * The deleter will be initialized with @p __d
291 */
292 template<typename _Del = deleter_type,
293 typename = _Require<is_copy_constructible<_Del>>>
294 unique_ptr(pointer __p, const deleter_type& __d) noexcept
295 : _M_t(__p, __d) { }
296
297 /** Takes ownership of a pointer.
298 *
299 * @param __p A pointer to an object of @c element_type
300 * @param __d An rvalue reference to a (non-reference) deleter.
301 *
302 * The deleter will be initialized with @p std::move(__d)
303 */
304 template<typename _Del = deleter_type,
305 typename = _Require<is_move_constructible<_Del>>>
306 unique_ptr(pointer __p,
307 __enable_if_t<!is_lvalue_reference<_Del>::value,
308 _Del&&> __d) noexcept
309 : _M_t(__p, std::move(__d))
310 { }
311
312 template<typename _Del = deleter_type,
313 typename _DelUnref = typename remove_reference<_Del>::type>
314 unique_ptr(pointer,
315 __enable_if_t<is_lvalue_reference<_Del>::value,
316 _DelUnref&&>) = delete;
317
318 /// Creates a unique_ptr that owns nothing.
319 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
320 constexpr unique_ptr(nullptr_t) noexcept
321 : _M_t()
322 { }
323
324 // Move constructors.
325
326 /// Move constructor.
327 unique_ptr(unique_ptr&&) = default;
328
329 /** @brief Converting constructor from another type
330 *
331 * Requires that the pointer owned by @p __u is convertible to the
332 * type of pointer owned by this object, @p __u does not own an array,
333 * and @p __u has a compatible deleter type.
334 */
335 template<typename _Up, typename _Ep, typename = _Require<
336 __safe_conversion_up<_Up, _Ep>,
337 typename conditional<is_reference<_Dp>::value,
338 is_same<_Ep, _Dp>,
339 is_convertible<_Ep, _Dp>>::type>>
340 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
341 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
342 { }
343
344#if _GLIBCXX_USE_DEPRECATED1
345#pragma GCC diagnostic push
346#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
347 /// Converting constructor from @c auto_ptr
348 template<typename _Up, typename = _Require<
349 is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>>
350 unique_ptr(auto_ptr<_Up>&& __u) noexcept;
351#pragma GCC diagnostic pop
352#endif
353
354 /// Destructor, invokes the deleter if the stored pointer is not null.
355 ~unique_ptr() noexcept
356 {
357 static_assert(__is_invocable<deleter_type&, pointer>::value,
358 "unique_ptr's deleter must be invocable with a pointer");
359 auto& __ptr = _M_t._M_ptr();
360 if (__ptr != nullptr)
361 get_deleter()(std::move(__ptr));
362 __ptr = pointer();
363 }
364
365 // Assignment.
366
367 /** @brief Move assignment operator.
368 *
369 * Invokes the deleter if this object owns a pointer.
370 */
371 unique_ptr& operator=(unique_ptr&&) = default;
372
373 /** @brief Assignment from another type.
374 *
375 * @param __u The object to transfer ownership from, which owns a
376 * convertible pointer to a non-array object.
377 *
378 * Invokes the deleter if this object owns a pointer.
379 */
380 template<typename _Up, typename _Ep>
381 typename enable_if< __and_<
382 __safe_conversion_up<_Up, _Ep>,
383 is_assignable<deleter_type&, _Ep&&>
384 >::value,
385 unique_ptr&>::type
386 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
387 {
388 reset(__u.release());
389 get_deleter() = std::forward<_Ep>(__u.get_deleter());
390 return *this;
391 }
392
393 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
394 unique_ptr&
395 operator=(nullptr_t) noexcept
396 {
397 reset();
398 return *this;
399 }
400
401 // Observers.
402
403 /// Dereference the stored pointer.
404 typename add_lvalue_reference<element_type>::type
405 operator*() const
406 {
407 __glibcxx_assert(get() != pointer());
408 return *get();
409 }
410
411 /// Return the stored pointer.
412 pointer
413 operator->() const noexcept
414 {
415 _GLIBCXX_DEBUG_PEDASSERT(get() != pointer());
416 return get();
417 }
418
419 /// Return the stored pointer.
420 pointer
421 get() const noexcept
422 { return _M_t._M_ptr(); }
423
424 /// Return a reference to the stored deleter.
425 deleter_type&
426 get_deleter() noexcept
427 { return _M_t._M_deleter(); }
428
429 /// Return a reference to the stored deleter.
430 const deleter_type&
431 get_deleter() const noexcept
432 { return _M_t._M_deleter(); }
433
434 /// Return @c true if the stored pointer is not null.
435 explicit operator bool() const noexcept
436 { return get() == pointer() ? false : true; }
437
438 // Modifiers.
439
440 /// Release ownership of any stored pointer.
441 pointer
442 release() noexcept
443 { return _M_t.release(); }
444
445 /** @brief Replace the stored pointer.
446 *
447 * @param __p The new pointer to store.
448 *
449 * The deleter will be invoked if a pointer is already owned.
450 */
451 void
452 reset(pointer __p = pointer()) noexcept
453 {
454 static_assert(__is_invocable<deleter_type&, pointer>::value,
455 "unique_ptr's deleter must be invocable with a pointer");
456 _M_t.reset(std::move(__p));
457 }
458
459 /// Exchange the pointer and deleter with another object.
460 void
461 swap(unique_ptr& __u) noexcept
462 {
463 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
464 _M_t.swap(__u._M_t);
465 }
466
467 // Disable copy from lvalue.
468 unique_ptr(const unique_ptr&) = delete;
469 unique_ptr& operator=(const unique_ptr&) = delete;
470 };
471
472 /// 20.7.1.3 unique_ptr for array objects with a runtime length
473 // [unique.ptr.runtime]
474 // _GLIBCXX_RESOLVE_LIB_DEFECTS
475 // DR 740 - omit specialization for array objects with a compile time length
476 template<typename _Tp, typename _Dp>
477 class unique_ptr<_Tp[], _Dp>
478 {
479 template <typename _Up>
480 using _DeleterConstraint =
481 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
482
483 __uniq_ptr_data<_Tp, _Dp> _M_t;
484
485 template<typename _Up>
486 using __remove_cv = typename remove_cv<_Up>::type;
487
488 // like is_base_of<_Tp, _Up> but false if unqualified types are the same
489 template<typename _Up>
490 using __is_derived_Tp
491 = __and_< is_base_of<_Tp, _Up>,
492 __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
493
494 public:
495 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
496 using element_type = _Tp;
497 using deleter_type = _Dp;
498
499 // helper template for detecting a safe conversion from another
500 // unique_ptr
501 template<typename _Up, typename _Ep,
502 typename _UPtr = unique_ptr<_Up, _Ep>,
503 typename _UP_pointer = typename _UPtr::pointer,
504 typename _UP_element_type = typename _UPtr::element_type>
505 using __safe_conversion_up = __and_<
506 is_array<_Up>,
507 is_same<pointer, element_type*>,
508 is_same<_UP_pointer, _UP_element_type*>,
509 is_convertible<_UP_element_type(*)[], element_type(*)[]>
510 >;
511
512 // helper template for detecting a safe conversion from a raw pointer
513 template<typename _Up>
514 using __safe_conversion_raw = __and_<
515 __or_<__or_<is_same<_Up, pointer>,
516 is_same<_Up, nullptr_t>>,
517 __and_<is_pointer<_Up>,
518 is_same<pointer, element_type*>,
519 is_convertible<
520 typename remove_pointer<_Up>::type(*)[],
521 element_type(*)[]>
522 >
523 >
524 >;
525
526 // Constructors.
527
528 /// Default constructor, creates a unique_ptr that owns nothing.
529 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
530 constexpr unique_ptr() noexcept
531 : _M_t()
532 { }
533
534 /** Takes ownership of a pointer.
535 *
536 * @param __p A pointer to an array of a type safely convertible
537 * to an array of @c element_type
538 *
539 * The deleter will be value-initialized.
540 */
541 template<typename _Up,
542 typename _Vp = _Dp,
543 typename = _DeleterConstraint<_Vp>,
544 typename = typename enable_if<
545 __safe_conversion_raw<_Up>::value, bool>::type>
546 explicit
547 unique_ptr(_Up __p) noexcept
548 : _M_t(__p)
549 { }
550
551 /** Takes ownership of a pointer.
552 *
553 * @param __p A pointer to an array of a type safely convertible
554 * to an array of @c element_type
555 * @param __d A reference to a deleter.
556 *
557 * The deleter will be initialized with @p __d
558 */
559 template<typename _Up, typename _Del = deleter_type,
560 typename = _Require<__safe_conversion_raw<_Up>,
561 is_copy_constructible<_Del>>>
562 unique_ptr(_Up __p, const deleter_type& __d) noexcept
563 : _M_t(__p, __d) { }
564
565 /** Takes ownership of a pointer.
566 *
567 * @param __p A pointer to an array of a type safely convertible
568 * to an array of @c element_type
569 * @param __d A reference to a deleter.
570 *
571 * The deleter will be initialized with @p std::move(__d)
572 */
573 template<typename _Up, typename _Del = deleter_type,
574 typename = _Require<__safe_conversion_raw<_Up>,
575 is_move_constructible<_Del>>>
576 unique_ptr(_Up __p,
577 __enable_if_t<!is_lvalue_reference<_Del>::value,
578 _Del&&> __d) noexcept
579 : _M_t(std::move(__p), std::move(__d))
580 { }
581
582 template<typename _Up, typename _Del = deleter_type,
583 typename _DelUnref = typename remove_reference<_Del>::type,
584 typename = _Require<__safe_conversion_raw<_Up>>>
585 unique_ptr(_Up,
586 __enable_if_t<is_lvalue_reference<_Del>::value,
587 _DelUnref&&>) = delete;
588
589 /// Move constructor.
590 unique_ptr(unique_ptr&&) = default;
591
592 /// Creates a unique_ptr that owns nothing.
593 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
594 constexpr unique_ptr(nullptr_t) noexcept
595 : _M_t()
596 { }
597
598 template<typename _Up, typename _Ep, typename = _Require<
599 __safe_conversion_up<_Up, _Ep>,
600 typename conditional<is_reference<_Dp>::value,
601 is_same<_Ep, _Dp>,
602 is_convertible<_Ep, _Dp>>::type>>
603 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
604 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
605 { }
606
607 /// Destructor, invokes the deleter if the stored pointer is not null.
608 ~unique_ptr()
609 {
610 auto& __ptr = _M_t._M_ptr();
611 if (__ptr != nullptr)
612 get_deleter()(__ptr);
613 __ptr = pointer();
614 }
615
616 // Assignment.
617
618 /** @brief Move assignment operator.
619 *
620 * Invokes the deleter if this object owns a pointer.
621 */
622 unique_ptr&
623 operator=(unique_ptr&&) = default;
624
625 /** @brief Assignment from another type.
626 *
627 * @param __u The object to transfer ownership from, which owns a
628 * convertible pointer to an array object.
629 *
630 * Invokes the deleter if this object owns a pointer.
631 */
632 template<typename _Up, typename _Ep>
633 typename
634 enable_if<__and_<__safe_conversion_up<_Up, _Ep>,
635 is_assignable<deleter_type&, _Ep&&>
636 >::value,
637 unique_ptr&>::type
638 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
639 {
640 reset(__u.release());
641 get_deleter() = std::forward<_Ep>(__u.get_deleter());
642 return *this;
643 }
644
645 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
646 unique_ptr&
647 operator=(nullptr_t) noexcept
648 {
649 reset();
650 return *this;
651 }
652
653 // Observers.
654
655 /// Access an element of owned array.
656 typename std::add_lvalue_reference<element_type>::type
657 operator[](size_t __i) const
658 {
659 __glibcxx_assert(get() != pointer());
660 return get()[__i];
661 }
662
663 /// Return the stored pointer.
664 pointer
665 get() const noexcept
666 { return _M_t._M_ptr(); }
667
668 /// Return a reference to the stored deleter.
669 deleter_type&
670 get_deleter() noexcept
671 { return _M_t._M_deleter(); }
672
673 /// Return a reference to the stored deleter.
674 const deleter_type&
675 get_deleter() const noexcept
676 { return _M_t._M_deleter(); }
677
678 /// Return @c true if the stored pointer is not null.
679 explicit operator bool() const noexcept
680 { return get() == pointer() ? false : true; }
7
Assuming the condition is false
8
'?' condition is false
9
Returning the value 1, which participates in a condition later
681
682 // Modifiers.
683
684 /// Release ownership of any stored pointer.
685 pointer
686 release() noexcept
687 { return _M_t.release(); }
688
689 /** @brief Replace the stored pointer.
690 *
691 * @param __p The new pointer to store.
692 *
693 * The deleter will be invoked if a pointer is already owned.
694 */
695 template <typename _Up,
696 typename = _Require<
697 __or_<is_same<_Up, pointer>,
698 __and_<is_same<pointer, element_type*>,
699 is_pointer<_Up>,
700 is_convertible<
701 typename remove_pointer<_Up>::type(*)[],
702 element_type(*)[]
703 >
704 >
705 >
706 >>
707 void
708 reset(_Up __p) noexcept
709 { _M_t.reset(std::move(__p)); }
710
711 void reset(nullptr_t = nullptr) noexcept
712 { reset(pointer()); }
713
714 /// Exchange the pointer and deleter with another object.
715 void
716 swap(unique_ptr& __u) noexcept
717 {
718 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
719 _M_t.swap(__u._M_t);
720 }
721
722 // Disable copy from lvalue.
723 unique_ptr(const unique_ptr&) = delete;
724 unique_ptr& operator=(const unique_ptr&) = delete;
725 };
726
727 /// @relates unique_ptr @{
728
729 /// Swap overload for unique_ptr
730 template<typename _Tp, typename _Dp>
731 inline
732#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
733 // Constrained free swap overload, see p0185r1
734 typename enable_if<__is_swappable<_Dp>::value>::type
735#else
736 void
737#endif
738 swap(unique_ptr<_Tp, _Dp>& __x,
739 unique_ptr<_Tp, _Dp>& __y) noexcept
740 { __x.swap(__y); }
741
742#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
743 template<typename _Tp, typename _Dp>
744 typename enable_if<!__is_swappable<_Dp>::value>::type
745 swap(unique_ptr<_Tp, _Dp>&,
746 unique_ptr<_Tp, _Dp>&) = delete;
747#endif
748
749 /// Equality operator for unique_ptr objects, compares the owned pointers
750 template<typename _Tp, typename _Dp,
751 typename _Up, typename _Ep>
752 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
753 operator==(const unique_ptr<_Tp, _Dp>& __x,
754 const unique_ptr<_Up, _Ep>& __y)
755 { return __x.get() == __y.get(); }
756
757 /// unique_ptr comparison with nullptr
758 template<typename _Tp, typename _Dp>
759 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
760 operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
761 { return !__x; }
762
763#ifndef __cpp_lib_three_way_comparison
764 /// unique_ptr comparison with nullptr
765 template<typename _Tp, typename _Dp>
766 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
767 operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
768 { return !__x; }
769
770 /// Inequality operator for unique_ptr objects, compares the owned pointers
771 template<typename _Tp, typename _Dp,
772 typename _Up, typename _Ep>
773 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
774 operator!=(const unique_ptr<_Tp, _Dp>& __x,
775 const unique_ptr<_Up, _Ep>& __y)
776 { return __x.get() != __y.get(); }
777
778 /// unique_ptr comparison with nullptr
779 template<typename _Tp, typename _Dp>
780 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
781 operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
782 { return (bool)__x; }
783
784 /// unique_ptr comparison with nullptr
785 template<typename _Tp, typename _Dp>
786 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
787 operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
788 { return (bool)__x; }
789#endif // three way comparison
790
791 /// Relational operator for unique_ptr objects, compares the owned pointers
792 template<typename _Tp, typename _Dp,
793 typename _Up, typename _Ep>
794 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
795 operator<(const unique_ptr<_Tp, _Dp>& __x,
796 const unique_ptr<_Up, _Ep>& __y)
797 {
798 typedef typename
799 std::common_type<typename unique_ptr<_Tp, _Dp>::pointer,
800 typename unique_ptr<_Up, _Ep>::pointer>::type _CT;
801 return std::less<_CT>()(__x.get(), __y.get());
802 }
803
804 /// unique_ptr comparison with nullptr
805 template<typename _Tp, typename _Dp>
806 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
807 operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
808 {
809 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
810 nullptr);
811 }
812
813 /// unique_ptr comparison with nullptr
814 template<typename _Tp, typename _Dp>
815 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
816 operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
817 {
818 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
819 __x.get());
820 }
821
822 /// Relational operator for unique_ptr objects, compares the owned pointers
823 template<typename _Tp, typename _Dp,
824 typename _Up, typename _Ep>
825 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
826 operator<=(const unique_ptr<_Tp, _Dp>& __x,
827 const unique_ptr<_Up, _Ep>& __y)
828 { return !(__y < __x); }
829
830 /// unique_ptr comparison with nullptr
831 template<typename _Tp, typename _Dp>
832 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
833 operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
834 { return !(nullptr < __x); }
835
836 /// unique_ptr comparison with nullptr
837 template<typename _Tp, typename _Dp>
838 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
839 operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
840 { return !(__x < nullptr); }
841
842 /// Relational operator for unique_ptr objects, compares the owned pointers
843 template<typename _Tp, typename _Dp,
844 typename _Up, typename _Ep>
845 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
846 operator>(const unique_ptr<_Tp, _Dp>& __x,
847 const unique_ptr<_Up, _Ep>& __y)
848 { return (__y < __x); }
849
850 /// unique_ptr comparison with nullptr
851 template<typename _Tp, typename _Dp>
852 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
853 operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
854 {
855 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
856 __x.get());
857 }
858
859 /// unique_ptr comparison with nullptr
860 template<typename _Tp, typename _Dp>
861 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
862 operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
863 {
864 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
865 nullptr);
866 }
867
868 /// Relational operator for unique_ptr objects, compares the owned pointers
869 template<typename _Tp, typename _Dp,
870 typename _Up, typename _Ep>
871 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
872 operator>=(const unique_ptr<_Tp, _Dp>& __x,
873 const unique_ptr<_Up, _Ep>& __y)
874 { return !(__x < __y); }
875
876 /// unique_ptr comparison with nullptr
877 template<typename _Tp, typename _Dp>
878 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
879 operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
880 { return !(__x < nullptr); }
881
882 /// unique_ptr comparison with nullptr
883 template<typename _Tp, typename _Dp>
884 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
885 operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
886 { return !(nullptr < __x); }
887
888#ifdef __cpp_lib_three_way_comparison
889 template<typename _Tp, typename _Dp, typename _Up, typename _Ep>
890 requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer,
891 typename unique_ptr<_Up, _Ep>::pointer>
892 inline
893 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer,
894 typename unique_ptr<_Up, _Ep>::pointer>
895 operator<=>(const unique_ptr<_Tp, _Dp>& __x,
896 const unique_ptr<_Up, _Ep>& __y)
897 { return compare_three_way()(__x.get(), __y.get()); }
898
899 template<typename _Tp, typename _Dp>
900 requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer>
901 inline
902 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer>
903 operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
904 {
905 using pointer = typename unique_ptr<_Tp, _Dp>::pointer;
906 return compare_three_way()(__x.get(), static_cast<pointer>(nullptr));
907 }
908#endif
909 // @} relates unique_ptr
910
911 /// @cond undocumented
912 template<typename _Up, typename _Ptr = typename _Up::pointer,
913 bool = __poison_hash<_Ptr>::__enable_hash_call>
914 struct __uniq_ptr_hash
915#if ! _GLIBCXX_INLINE_VERSION0
916 : private __poison_hash<_Ptr>
917#endif
918 {
919 size_t
920 operator()(const _Up& __u) const
921 noexcept(noexcept(std::declval<hash<_Ptr>>()(std::declval<_Ptr>())))
922 { return hash<_Ptr>()(__u.get()); }
923 };
924
925 template<typename _Up, typename _Ptr>
926 struct __uniq_ptr_hash<_Up, _Ptr, false>
927 : private __poison_hash<_Ptr>
928 { };
929 /// @endcond
930
931 /// std::hash specialization for unique_ptr.
932 template<typename _Tp, typename _Dp>
933 struct hash<unique_ptr<_Tp, _Dp>>
934 : public __hash_base<size_t, unique_ptr<_Tp, _Dp>>,
935 public __uniq_ptr_hash<unique_ptr<_Tp, _Dp>>
936 { };
937
938#if __cplusplus201703L >= 201402L
939 /// @relates unique_ptr @{
940#define __cpp_lib_make_unique201304 201304
941
942 /// @cond undocumented
943
944 template<typename _Tp>
945 struct _MakeUniq
946 { typedef unique_ptr<_Tp> __single_object; };
947
948 template<typename _Tp>
949 struct _MakeUniq<_Tp[]>
950 { typedef unique_ptr<_Tp[]> __array; };
951
952 template<typename _Tp, size_t _Bound>
953 struct _MakeUniq<_Tp[_Bound]>
954 { struct __invalid_type { }; };
955
956 /// @endcond
957
958 /// std::make_unique for single objects
959 template<typename _Tp, typename... _Args>
960 inline typename _MakeUniq<_Tp>::__single_object
961 make_unique(_Args&&... __args)
962 { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
963
964 /// std::make_unique for arrays of unknown bound
965 template<typename _Tp>
966 inline typename _MakeUniq<_Tp>::__array
967 make_unique(size_t __num)
968 { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
969
970 /// Disable std::make_unique for arrays of known bound
971 template<typename _Tp, typename... _Args>
972 inline typename _MakeUniq<_Tp>::__invalid_type
973 make_unique(_Args&&...) = delete;
974 // @} relates unique_ptr
975#endif // C++14
976
977#if __cplusplus201703L > 201703L && __cpp_concepts
978 // _GLIBCXX_RESOLVE_LIB_DEFECTS
979 // 2948. unique_ptr does not define operator<< for stream output
980 /// Stream output operator for unique_ptr
981 template<typename _CharT, typename _Traits, typename _Tp, typename _Dp>
982 inline basic_ostream<_CharT, _Traits>&
983 operator<<(basic_ostream<_CharT, _Traits>& __os,
984 const unique_ptr<_Tp, _Dp>& __p)
985 requires requires { __os << __p.get(); }
986 {
987 __os << __p.get();
988 return __os;
989 }
990#endif // C++20
991
992 // @} group pointer_abstractions
993
994#if __cplusplus201703L >= 201703L
995 namespace __detail::__variant
996 {
997 template<typename> struct _Never_valueless_alt; // see <variant>
998
999 // Provide the strong exception-safety guarantee when emplacing a
1000 // unique_ptr into a variant.
1001 template<typename _Tp, typename _Del>
1002 struct _Never_valueless_alt<std::unique_ptr<_Tp, _Del>>
1003 : std::true_type
1004 { };
1005 } // namespace __detail::__variant
1006#endif // C++17
1007
1008_GLIBCXX_END_NAMESPACE_VERSION
1009} // namespace
1010
1011#endif /* _UNIQUE_PTR_H */