Commit c7e877b88b7e0c9a4608e16df777ded5dd8f6593
1 parent
ef2b84c6
Update documentation for PointerHolder transition
Showing
3 changed files
with
120 additions
and
222 deletions
README-maintainer
| @@ -160,11 +160,16 @@ CODING RULES | @@ -160,11 +160,16 @@ CODING RULES | ||
| 160 | it seems also for classes that are intended to be subclassed across | 160 | it seems also for classes that are intended to be subclassed across |
| 161 | the shared library boundary. | 161 | the shared library boundary. |
| 162 | 162 | ||
| 163 | -* Put private member variables in PointerHolder<Members> for all | 163 | +* Put private member variables in std::shared_ptr<Members> for all |
| 164 | public classes. Remember to use QPDF_DLL on ~Members(). Exception: | 164 | public classes. Remember to use QPDF_DLL on ~Members(). Exception: |
| 165 | - indirection through PointerHolder<Members> is expensive, so don't do | ||
| 166 | - it for classes that are copied a lot, like QPDFObjectHandle and | ||
| 167 | - QPDFObject. | 165 | + indirection through std::shared_ptr<Members> is expensive, so don't |
| 166 | + do it for classes that are copied a lot, like QPDFObjectHandle and | ||
| 167 | + QPDFObject. It may be possible to declare | ||
| 168 | + std::shared_ptr<Members> m_ph; | ||
| 169 | + Member* m; | ||
| 170 | + with m = m_ph.get(), and then indirect through m in | ||
| 171 | + performance-critical settings, though in 2022, std::shared_ptr is | ||
| 172 | + sufficiently performant that this may not be worth it. | ||
| 168 | 173 | ||
| 169 | * Traversal of objects is expensive. It's worth adding some complexity | 174 | * Traversal of objects is expensive. It's worth adding some complexity |
| 170 | to avoid needless traversals of objects. | 175 | to avoid needless traversals of objects. |
TODO
| @@ -5,8 +5,7 @@ Next | @@ -5,8 +5,7 @@ Next | ||
| 5 | * At next release, hide release-qpdf-10.6.3.0cmake* versions at readthedocs | 5 | * At next release, hide release-qpdf-10.6.3.0cmake* versions at readthedocs |
| 6 | 6 | ||
| 7 | In order: | 7 | In order: |
| 8 | -* cmake | ||
| 9 | -* PointerHolder -> shared_ptr | 8 | +* cmake -- remaining steps |
| 10 | * ABI including --json default is latest | 9 | * ABI including --json default is latest |
| 11 | * json v2 | 10 | * json v2 |
| 12 | 11 | ||
| @@ -29,9 +28,6 @@ Misc | @@ -29,9 +28,6 @@ Misc | ||
| 29 | --show-encryption could potentially retry with this option if the | 28 | --show-encryption could potentially retry with this option if the |
| 30 | first time doesn't work. Then, with the file open, we can read the | 29 | first time doesn't work. Then, with the file open, we can read the |
| 31 | encryption dictionary normally. | 30 | encryption dictionary normally. |
| 32 | -* Go through README-maintainer "CODING RULES" and update -- | ||
| 33 | - PointerHolder and other changes will make some of the rules | ||
| 34 | - obsolete. | ||
| 35 | * Have a warn in QPDF that passes its variable arguments onto QPDFExc | 31 | * Have a warn in QPDF that passes its variable arguments onto QPDFExc |
| 36 | so you don't have to do warn(QPDFExc(...)) | 32 | so you don't have to do warn(QPDFExc(...)) |
| 37 | 33 | ||
| @@ -57,6 +53,7 @@ cmake | @@ -57,6 +53,7 @@ cmake | ||
| 57 | QPDF_DLL are public because QPDF_DLL_LOCAL makes the other things | 53 | QPDF_DLL are public because QPDF_DLL_LOCAL makes the other things |
| 58 | private. See https://gcc.gnu.org/wiki/Visibility. Make sure this | 54 | private. See https://gcc.gnu.org/wiki/Visibility. Make sure this |
| 59 | is documented. | 55 | is documented. |
| 56 | + * Update "CODING RULES" in "README-maintainer" - search for QPDF_DLL | ||
| 60 | * Nice to have: | 57 | * Nice to have: |
| 61 | * Split qpdf.test into multiple tests | 58 | * Split qpdf.test into multiple tests |
| 62 | * Rework tests so that nothing is written into the source directory. | 59 | * Rework tests so that nothing is written into the source directory. |
| @@ -500,103 +497,6 @@ Other notes: | @@ -500,103 +497,6 @@ Other notes: | ||
| 500 | way that works for the qpdf/qpdf repository as well since they are | 497 | way that works for the qpdf/qpdf repository as well since they are |
| 501 | very similar. | 498 | very similar. |
| 502 | 499 | ||
| 503 | -PointerHolder to std::shared_ptr | ||
| 504 | -================================ | ||
| 505 | - | ||
| 506 | -To perform update: | ||
| 507 | - | ||
| 508 | -Cherry-pick pointerholder branch commit | ||
| 509 | - | ||
| 510 | -Upgrade just the library. This is not necessary, but it's an added | ||
| 511 | -check that the compatibility code works since it will show that tests, | ||
| 512 | -examples, and CLI will work properly with the upgraded APIs, which | ||
| 513 | -provides some assurance that other people will have a smooth time with | ||
| 514 | -their code. | ||
| 515 | - | ||
| 516 | -patrepl s/PointerHolder/std::shared_ptr/g {include,libqpdf}/qpdf/*.hh | ||
| 517 | -patrepl s/PointerHolder/std::shared_ptr/g libqpdf/*.cc | ||
| 518 | -patrepl s/make_pointer_holder/std::make_shared/g libqpdf/*.cc | ||
| 519 | -patrepl s/make_array_pointer_holder/QUtil::make_shared_array/g libqpdf/*.cc | ||
| 520 | -patrepl s,qpdf/std::shared_ptr,qpdf/PointerHolder, **/*.cc **/*.hh | ||
| 521 | -git restore include/qpdf/PointerHolder.hh | ||
| 522 | -cleanpatch | ||
| 523 | - | ||
| 524 | -Increase to POINTERHOLDER_TRANSITION=3 | ||
| 525 | - | ||
| 526 | -make build_libqpdf -- no errors | ||
| 527 | - | ||
| 528 | -Drop back to POINTERHOLDER_TRANSITION=2 | ||
| 529 | - | ||
| 530 | -make check -- everything passes | ||
| 531 | - | ||
| 532 | -Then upgrade everything else. It would work to just start here. | ||
| 533 | - | ||
| 534 | -Increase to POINTERHOLDER_TRANSITION=3 | ||
| 535 | - | ||
| 536 | -patrepl s/PointerHolder/std::shared_ptr/g **/*.cc **/*.hh | ||
| 537 | -patrepl s/make_pointer_holder/std::make_shared/g **/*.cc | ||
| 538 | -patrepl s/make_array_pointer_holder/QUtil::make_shared_array/g **/*.cc | ||
| 539 | -patrepl s,qpdf/std::shared_ptr,qpdf/PointerHolder, **/*.cc **/*.hh | ||
| 540 | -git restore include/qpdf/PointerHolder.hh | ||
| 541 | -git restore libtests/pointer_holder.cc | ||
| 542 | -cleanpatch | ||
| 543 | - | ||
| 544 | -Remove all references to PointerHolder.hh from everything except | ||
| 545 | -public headers and pointer_holder.cc. | ||
| 546 | - | ||
| 547 | -make check -- everything passes | ||
| 548 | - | ||
| 549 | -Increase to POINTERHOLDER_TRANSITION=4 | ||
| 550 | - | ||
| 551 | -Do a clean build and make check -- everything passes | ||
| 552 | - | ||
| 553 | -Final steps: | ||
| 554 | - | ||
| 555 | -* Change to POINTERHOLDER_TRANSITION=4 | ||
| 556 | -* Check code formatting | ||
| 557 | -* std::shared_ptr<Members> m can be replaced with | ||
| 558 | - std::shared_ptr<Members> m_ph and Members* m if performance is critical | ||
| 559 | -* Could try Members indirection with Members* for QPDFObjectHandle | ||
| 560 | - | ||
| 561 | -When done: | ||
| 562 | - | ||
| 563 | -* Update the smart-pointers section of the manual in design.rst | ||
| 564 | -* Update comments in PointerHolder.hh | ||
| 565 | - | ||
| 566 | -PointerHolder in public API: | ||
| 567 | - | ||
| 568 | - PointerHolder<Buffer> Pl_Buffer::getBufferSharedPointer(); | ||
| 569 | - PointerHolder<Buffer> QPDFWriter::getBufferSharedPointer(); | ||
| 570 | - QUtil::read_file_into_memory( | ||
| 571 | - char const*, PointerHolder<char>&, unsigned long&) | ||
| 572 | - QPDFObjectHandle::addContentTokenFilter( | ||
| 573 | - PointerHolder<QPDFObjectHandle::TokenFilter>) | ||
| 574 | - QPDFObjectHandle::addTokenFilter( | ||
| 575 | - PointerHolder<QPDFObjectHandle::TokenFilter>) | ||
| 576 | - QPDFObjectHandle::newStream( | ||
| 577 | - QPDF*, PointerHolder<Buffer>) | ||
| 578 | - QPDFObjectHandle::parse( | ||
| 579 | - PointerHolder<InputSource>, std::string const&, | ||
| 580 | - QPDFTokenizer&, bool&, QPDFObjectHandle::StringDecrypter*, QPDF*) | ||
| 581 | - QPDFObjectHandle::replaceStreamData( | ||
| 582 | - PointerHolder<Buffer>, QPDFObjectHandle const&, | ||
| 583 | - QPDFObjectHandle const&) | ||
| 584 | - QPDFObjectHandle::replaceStreamData( | ||
| 585 | - PointerHolder<QPDFObjectHandle::StreamDataProvider>, | ||
| 586 | - QPDFObjectHandle const&, QPDFObjectHandle const&) | ||
| 587 | - QPDFTokenizer::expectInlineImage( | ||
| 588 | - PointerHolder<InputSource>) | ||
| 589 | - QPDFTokenizer::readToken( | ||
| 590 | - PointerHolder<InputSource>, std::string const&, | ||
| 591 | - bool, unsigned long) | ||
| 592 | - QPDF::processInputSource( | ||
| 593 | - PointerHolder<InputSource>, char const*) | ||
| 594 | - QPDFWriter::registerProgressReporter( | ||
| 595 | - PointerHolder<QPDFWriter::ProgressReporter>) | ||
| 596 | - QPDFEFStreamObjectHelper::createEFStream( | ||
| 597 | - QPDF&, PointerHolder<Buffer>) | ||
| 598 | - QPDFPageObjectHelper::addContentTokenFilter( | ||
| 599 | - PointerHolder<QPDFObjectHandle::TokenFilter>) | ||
| 600 | 500 | ||
| 601 | ABI Changes | 501 | ABI Changes |
| 602 | =========== | 502 | =========== |
manual/design.rst
| @@ -53,13 +53,11 @@ or not if this information is needed. All access to objects deals with | @@ -53,13 +53,11 @@ or not if this information is needed. All access to objects deals with | ||
| 53 | this transparently. All memory management details are also handled by | 53 | this transparently. All memory management details are also handled by |
| 54 | the library. | 54 | the library. |
| 55 | 55 | ||
| 56 | -The ``PointerHolder`` object is used internally by the library to deal | ||
| 57 | -with memory management. This is basically a smart pointer object very | ||
| 58 | -similar in spirit to C++-11's ``std::shared_ptr`` object, but predating | ||
| 59 | -it by several years. This library also makes use of a technique for | ||
| 60 | -giving fine-grained access to methods in one class to other classes by | ||
| 61 | -using public subclasses with friends and only private members that in | ||
| 62 | -turn call private methods of the containing class. See | 56 | +Memory is managed mostly with ``std::shared_ptr`` object to minimize |
| 57 | +explicit memory handling. This library also makes use of a technique | ||
| 58 | +for giving fine-grained access to methods in one class to other | ||
| 59 | +classes by using public subclasses with friends and only private | ||
| 60 | +members that in turn call private methods of the containing class. See | ||
| 63 | ``QPDFObjectHandle::Factory`` as an example. | 61 | ``QPDFObjectHandle::Factory`` as an example. |
| 64 | 62 | ||
| 65 | The top-level qpdf class is ``QPDF``. A ``QPDF`` object represents a PDF | 63 | The top-level qpdf class is ``QPDF``. A ``QPDF`` object represents a PDF |
| @@ -68,13 +66,14 @@ files. | @@ -68,13 +66,14 @@ files. | ||
| 68 | 66 | ||
| 69 | The primary class for interacting with PDF objects is | 67 | The primary class for interacting with PDF objects is |
| 70 | ``QPDFObjectHandle``. Instances of this class can be passed around by | 68 | ``QPDFObjectHandle``. Instances of this class can be passed around by |
| 71 | -value, copied, stored in containers, etc. with very low overhead. | ||
| 72 | -Instances of ``QPDFObjectHandle`` created by reading from a file will | ||
| 73 | -always contain a reference back to the ``QPDF`` object from which they | ||
| 74 | -were created. A ``QPDFObjectHandle`` may be direct or indirect. If | ||
| 75 | -indirect, the ``QPDFObject`` the ``PointerHolder`` initially points to | ||
| 76 | -is a null pointer. In this case, the first attempt to access the | ||
| 77 | -underlying ``QPDFObject`` will result in the ``QPDFObject`` being | 69 | +value, copied, stored in containers, etc. with very low overhead. The |
| 70 | +``QPDFObjectHandle`` object contains an internal shared pointer to an | ||
| 71 | +underyling ``QPDFObject``. Instances of ``QPDFObjectHandle`` created | ||
| 72 | +by reading from a file will always contain a reference back to the | ||
| 73 | +``QPDF`` object from which they were created. A ``QPDFObjectHandle`` | ||
| 74 | +may be direct or indirect. If indirect, the ``QPDFObject`` shared | ||
| 75 | +pointer is initially null. In this case, the first attempt to access | ||
| 76 | +the underlying ``QPDFObject`` will result in the ``QPDFObject`` being | ||
| 78 | resolved via a call to the referenced ``QPDF`` instance. This makes it | 77 | resolved via a call to the referenced ``QPDF`` instance. This makes it |
| 79 | essentially impossible to make coding errors in which certain things | 78 | essentially impossible to make coding errors in which certain things |
| 80 | will work for some PDF files and not for others based on which objects | 79 | will work for some PDF files and not for others based on which objects |
| @@ -248,17 +247,18 @@ During this process, the "``R``" keyword is recognized and an indirect | @@ -248,17 +247,18 @@ During this process, the "``R``" keyword is recognized and an indirect | ||
| 248 | 247 | ||
| 249 | The ``QPDF::resolve()`` method, which is used to resolve an indirect | 248 | The ``QPDF::resolve()`` method, which is used to resolve an indirect |
| 250 | object, may be invoked from the ``QPDFObjectHandle`` class. It first | 249 | object, may be invoked from the ``QPDFObjectHandle`` class. It first |
| 251 | -checks a cache to see whether this object has already been read. If not, | ||
| 252 | -it reads the object from the PDF file and caches it. It the returns the | ||
| 253 | -resulting ``QPDFObjectHandle``. The calling object handle then replaces | ||
| 254 | -its ``PointerHolder<QDFObject>`` with the one from the newly returned | ||
| 255 | -``QPDFObjectHandle``. In this way, only a single copy of any direct | ||
| 256 | -object need exist and clients can access objects transparently without | ||
| 257 | -knowing or caring whether they are direct or indirect objects. | ||
| 258 | -Additionally, no object is ever read from the file more than once. That | ||
| 259 | -means that only the portions of the PDF file that are actually needed | ||
| 260 | -are ever read from the input file, thus allowing the qpdf package to | ||
| 261 | -take advantage of this important design goal of PDF files. | 250 | +checks a cache to see whether this object has already been read. If |
| 251 | +not, it reads the object from the PDF file and caches it. It the | ||
| 252 | +returns the resulting ``QPDFObjectHandle``. The calling object handle | ||
| 253 | +then replaces its ``std::shared_ptr<QDFObject>`` with the one from the | ||
| 254 | +newly returned ``QPDFObjectHandle``. In this way, only a single copy | ||
| 255 | +of any direct object need exist and clients can access objects | ||
| 256 | +transparently without knowing or caring whether they are direct or | ||
| 257 | +indirect objects. Additionally, no object is ever read from the file | ||
| 258 | +more than once. That means that only the portions of the PDF file that | ||
| 259 | +are actually needed are ever read from the input file, thus allowing | ||
| 260 | +the qpdf package to take advantage of this important design goal of | ||
| 261 | +PDF files. | ||
| 262 | 262 | ||
| 263 | If the requested object is inside of an object stream, the object stream | 263 | If the requested object is inside of an object stream, the object stream |
| 264 | itself is first read into memory. Then the tokenizer reads objects from | 264 | itself is first read into memory. Then the tokenizer reads objects from |
| @@ -762,40 +762,47 @@ Smart Pointers | @@ -762,40 +762,47 @@ Smart Pointers | ||
| 762 | -------------- | 762 | -------------- |
| 763 | 763 | ||
| 764 | This section describes changes to the use of smart pointers that were | 764 | This section describes changes to the use of smart pointers that were |
| 765 | -made in qpdf 10.6.0 as well as some planned for 11.0.0. | 765 | +made in qpdf 10.6.0 and 11.0.0. |
| 766 | 766 | ||
| 767 | -Starting in qpdf 11, ``PointerHolder`` will be replaced with | 767 | +In qpdf 11.0.0, ``PointerHolder`` was replaced with |
| 768 | ``std::shared_ptr`` in qpdf's public API. A backward-compatible | 768 | ``std::shared_ptr`` in qpdf's public API. A backward-compatible |
| 769 | -``PointerHolder`` class will be provided that should make it possible | ||
| 770 | -for most code to remain unchanged. ``PointerHolder`` may eventually be | 769 | +``PointerHolder`` class has been provided that makes it possible for |
| 770 | +most code to remain unchanged. ``PointerHolder`` may eventually be | ||
| 771 | removed from qpdf entirely, but this will not happen for a while to | 771 | removed from qpdf entirely, but this will not happen for a while to |
| 772 | make it easier for people who need to support multiple versions of | 772 | make it easier for people who need to support multiple versions of |
| 773 | qpdf. | 773 | qpdf. |
| 774 | 774 | ||
| 775 | -The ``POINTERHOLDER_TRANSITION`` preprocessor symbol has been | ||
| 776 | -introduced to help people transition from ``PointerHolder`` to | ||
| 777 | -``std::shared_ptr``. After qpdf 11 is released, to prepare for a | ||
| 778 | -future qpdf without ``PointerHolder`` and to let them know that it is | ||
| 779 | -no longer needed, a warning will be issued if | ||
| 780 | -``<qpdf/PointerHolder.hh>`` is included, though it will be possible to | ||
| 781 | -suppress the warning by defining ``POINTERHOLDER_TRANSITION``. In | ||
| 782 | -10.6.0, there are some steps you can perform to prepare, but no action | ||
| 783 | -is required. | 775 | +In 10.6.0, some enhancements were made to ``PointerHolder`` to ease |
| 776 | +the transition. These intermediate steps are relevant only for | ||
| 777 | +versions 10.6.0 through 10.6.3 but can still help with incremental | ||
| 778 | +modification of code. | ||
| 784 | 779 | ||
| 785 | -The remainder of this section describes how to prepare if you want to | ||
| 786 | -eliminate ``PointerHolder`` from your code or what to do if you want | ||
| 787 | -to stick with the old interfaces. | 780 | +The ``POINTERHOLDER_TRANSITION`` preprocessor symbol was introduced in |
| 781 | +qpdf 10.6.0 to help people transition from ``PointerHolder`` to | ||
| 782 | +``std::shared_ptr``. If you don't define this, you will get a compiler | ||
| 783 | +warning. Defining it to any value will suppress the warning. An | ||
| 784 | +explanation appears below of the different possible values for this | ||
| 785 | +symbol and what they mean. | ||
| 788 | 786 | ||
| 789 | -Changes in 10.6.0 | ||
| 790 | -~~~~~~~~~~~~~~~~~ | 787 | +Starting in qpdf 11.0.0, including ``<qpdf/PointerHolder.hh>`` defines |
| 788 | +the symbol ``POINTERHOLDER_IS_SHARED_POINTER``. This can be used with | ||
| 789 | +conditional compilation to make it possible to support different | ||
| 790 | +versions of qpdf. | ||
| 791 | 791 | ||
| 792 | -In qpdf 10.6.0, the following changes have been made to | ||
| 793 | -``PointerHolder`` to make its behavior closer to that of | ||
| 794 | -``std::shared_ptr``: | 792 | +The rest of this section provides the details. |
| 795 | 793 | ||
| 796 | -- ``get()`` has been added as an alternative to ``getPointer()`` | 794 | +Transitional Enhancements to PointerHolder |
| 795 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 797 | 796 | ||
| 798 | -- ``use_count()`` has been added as an alternative to ``getRefcount()`` | 797 | +In qpdf 10.6.0, some changes were to ``PointerHolder`` to make it |
| 798 | +easier to prepare for the transition to ``std::shared_ptr``. These | ||
| 799 | +enhancements also make it easier to incrementally upgrade your code. | ||
| 800 | +The following changes were made to ``PointerHolder`` to make its | ||
| 801 | +behavior closer to that of ``std::shared_ptr``: | ||
| 802 | + | ||
| 803 | +- ``get()`` was added as an alternative to ``getPointer()`` | ||
| 804 | + | ||
| 805 | +- ``use_count()`` was added as an alternative to ``getRefcount()`` | ||
| 799 | 806 | ||
| 800 | - A new global helper function ``make_pointer_holder`` behaves | 807 | - A new global helper function ``make_pointer_holder`` behaves |
| 801 | similarly to ``std::make_shared``, so you can use | 808 | similarly to ``std::make_shared``, so you can use |
| @@ -807,7 +814,7 @@ In qpdf 10.6.0, the following changes have been made to | @@ -807,7 +814,7 @@ In qpdf 10.6.0, the following changes have been made to | ||
| 807 | counterpart to the newly added ``QUtil::make_shared_array`` method, | 814 | counterpart to the newly added ``QUtil::make_shared_array`` method, |
| 808 | which does the same thing with a ``std::shared_ptr``. | 815 | which does the same thing with a ``std::shared_ptr``. |
| 809 | 816 | ||
| 810 | -``PointerHolder`` has had a long-standing bug: a ``const | 817 | +``PointerHolder`` had a long-standing bug: a ``const |
| 811 | PointerHolder<T>`` would only provide a ``T const*`` with its | 818 | PointerHolder<T>`` would only provide a ``T const*`` with its |
| 812 | ``getPointer`` method. This is incorrect and is not how standard | 819 | ``getPointer`` method. This is incorrect and is not how standard |
| 813 | library C++ smart pointers or regular pointers behave. The correct | 820 | library C++ smart pointers or regular pointers behave. The correct |
| @@ -873,16 +880,23 @@ preprocessor symbol or other C++ coding techniques. | @@ -873,16 +880,23 @@ preprocessor symbol or other C++ coding techniques. | ||
| 873 | pointer. It also has the seldom-used ``getRefcount()`` method to get | 880 | pointer. It also has the seldom-used ``getRefcount()`` method to get |
| 874 | the reference count. ``std::shared_ptr<T>`` has ``get()`` and | 881 | the reference count. ``std::shared_ptr<T>`` has ``get()`` and |
| 875 | ``use_count()``. In qpdf 10.6, ``PointerHolder<T>`` also has | 882 | ``use_count()``. In qpdf 10.6, ``PointerHolder<T>`` also has |
| 876 | - would not be an issue unless you did this in your own code. | 883 | + ``get()`` and ``use_count()``. |
| 877 | 884 | ||
| 878 | Addressing the Differences | 885 | Addressing the Differences |
| 879 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 886 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 880 | 887 | ||
| 881 | -If you need to support versions of qpdf prior to qpdf 10.6, you don't | ||
| 882 | -*need* to take any action at this time, but it is recommended that you | ||
| 883 | -at least address the implicit constructor issue since this can be done | ||
| 884 | -without breaking backward compatibility. (Explicit construction of | ||
| 885 | -``PointerHolder<T>`` is and always has been allowed.) | 888 | +If you are not ready to take action yet, you can ``#define |
| 889 | +POINTERHOLDER_TRANSITION 0`` before including any qpdf header file or | ||
| 890 | +add the definition of that symbol to your build. This will provide the | ||
| 891 | +backward-compatible ``PointerHolder`` API without any deprecation | ||
| 892 | +warnings. This should be a temporary measure as ``PointerHolder`` may | ||
| 893 | +disappear in the future. If you need to be able to support newer and | ||
| 894 | +older versions of qpdf, there are other options, explained below. | ||
| 895 | + | ||
| 896 | +Note that, even with ``0``, you should rebuild and test your code. | ||
| 897 | +There may be compiler errors if you have containers of | ||
| 898 | +``PointerHolder``, but most code should compile without any changes. | ||
| 899 | +There are no uses of containers of ``PointerHolder`` in qpdf's API. | ||
| 886 | 900 | ||
| 887 | There are two significant things you can do to minimize the impact of | 901 | There are two significant things you can do to minimize the impact of |
| 888 | switching from ``PointerHolder`` to ``std::shared_ptr``: | 902 | switching from ``PointerHolder`` to ``std::shared_ptr``: |
| @@ -908,31 +922,35 @@ without consulting this manual. | @@ -908,31 +922,35 @@ without consulting this manual. | ||
| 908 | - meaning | 922 | - meaning |
| 909 | 923 | ||
| 910 | - - undefined | 924 | - - undefined |
| 911 | - - Same as ``0``, but starting with qpdf 11.0, issues a warning | 925 | + - Same as ``0`` but issues a warning |
| 912 | 926 | ||
| 913 | - - ``0`` | 927 | - - ``0`` |
| 914 | - Provide a backward compatible ``PointerHolder`` and suppress | 928 | - Provide a backward compatible ``PointerHolder`` and suppress |
| 915 | - all deprecation warnings | 929 | + all deprecation warnings; supports all prior qpdf versions |
| 916 | 930 | ||
| 917 | - - ``1`` | 931 | - - ``1`` |
| 918 | - - Make the ``PointerHolder<T>(T*)`` constructor explicit | 932 | + - Make the ``PointerHolder<T>(T*)`` constructor explicit; |
| 933 | + resulting code supports all prior qpdf versions | ||
| 919 | 934 | ||
| 920 | - - ``2`` | 935 | - - ``2`` |
| 921 | - - Deprecate ``getPointer()`` and ``getRefcount()`` | 936 | + - Deprecate ``getPointer()`` and ``getRefcount()``; requires |
| 937 | + qpdf 10.6.0 or later. | ||
| 922 | 938 | ||
| 923 | - - ``3`` | 939 | - - ``3`` |
| 924 | - - Starting with qpdf 11.0, deprecate all uses of ``PointerHolder`` | 940 | + - Deprecate all uses of ``PointerHolder``; requires qpdf 11.0.0 |
| 941 | + or later | ||
| 925 | 942 | ||
| 926 | - - ``4`` | 943 | - - ``4`` |
| 927 | - - Starting with qpdf 11.0, disable all functionality from | ||
| 928 | - ``qpdf/PointerHolder.hh`` so that ``#include``-ing it has no | ||
| 929 | - effect. | 944 | + - Disable all functionality from ``qpdf/PointerHolder.hh`` so |
| 945 | + that ``#include``-ing it has no effect other than defining | ||
| 946 | + ``POINTERHOLDER_IS_SHARED_POINTER``; requires qpdf 11.0.0 or | ||
| 947 | + later. | ||
| 930 | 948 | ||
| 931 | Based on the above, here is a procedure for preparing your code. This | 949 | Based on the above, here is a procedure for preparing your code. This |
| 932 | is the procedure that was used for the qpdf code itself. | 950 | is the procedure that was used for the qpdf code itself. |
| 933 | 951 | ||
| 934 | -If you need to support versions of qpdf prior to 10.6, you can still | ||
| 935 | -do these steps: | 952 | +You can do these steps without breaking support for qpdf versions |
| 953 | +before 10.6.0: | ||
| 936 | 954 | ||
| 937 | - Find all occurrences of ``PointerHolder`` in the code. See whether | 955 | - Find all occurrences of ``PointerHolder`` in the code. See whether |
| 938 | any of them can just be outright replaced with ``std::shared_ptr`` | 956 | any of them can just be outright replaced with ``std::shared_ptr`` |
| @@ -974,8 +992,9 @@ do these steps: | @@ -974,8 +992,9 @@ do these steps: | ||
| 974 | auto p = std::unique_ptr<X[]>(new X[n]); | 992 | auto p = std::unique_ptr<X[]>(new X[n]); |
| 975 | 993 | ||
| 976 | - If a ``PointerHolder<T>`` can't be replaced with a standard library | 994 | - If a ``PointerHolder<T>`` can't be replaced with a standard library |
| 977 | - smart pointer, perhaps it can be declared using ``auto`` or | ||
| 978 | - ``decltype`` so that, when the qpdf API changes, your code will just | 995 | + smart pointer because it is used with an older qpdf API call, |
| 996 | + perhaps it can be declared using ``auto`` or ``decltype`` so that, | ||
| 997 | + when building with a newer qpdf API changes, your code will just | ||
| 979 | need to be recompiled. | 998 | need to be recompiled. |
| 980 | 999 | ||
| 981 | - ``#define POINTERHOLDER_TRANSITION 1`` to enable deprecation | 1000 | - ``#define POINTERHOLDER_TRANSITION 1`` to enable deprecation |
| @@ -1000,55 +1019,18 @@ do these steps: | @@ -1000,55 +1019,18 @@ do these steps: | ||
| 1000 | Other examples appear above. | 1019 | Other examples appear above. |
| 1001 | 1020 | ||
| 1002 | If you need to support older versions of qpdf than 10.6, this is as | 1021 | If you need to support older versions of qpdf than 10.6, this is as |
| 1003 | -far as you can go until qpdf 11 comes out. | ||
| 1004 | - | ||
| 1005 | -If you only need to support the latest version of qpdf, proceed as | ||
| 1006 | -follows: | ||
| 1007 | - | ||
| 1008 | -- ``#define POINTERHOLDER_TRANSITION 2`` to enable deprecation of | ||
| 1009 | - ``getPointer()`` and ``getRefcount()`` | ||
| 1010 | - | ||
| 1011 | -- Replace ``getPointer()`` with ``get()`` and ``getRefcount()`` with | ||
| 1012 | - ``use_count()``. These methods were not present prior to 10.6.0. | 1022 | +far as you can go without conditional compilation. |
| 1013 | 1023 | ||
| 1014 | -When you have gotten your code to compile cleanly with | ||
| 1015 | -``POINTERHOLDER_TRANSITION=2``, you are well on your way to being | ||
| 1016 | -ready for eliminating ``PointerHolder`` entirely after qpdf 11 is | ||
| 1017 | -released. | ||
| 1018 | - | ||
| 1019 | -After qpdf 11 is out | ||
| 1020 | -~~~~~~~~~~~~~~~~~~~~ | ||
| 1021 | - | ||
| 1022 | -In the 10.6 manual, this section represents a plan and is subject to | ||
| 1023 | -change. However, it has been tested in practice using a version of the | ||
| 1024 | -qpdf 11 ``PointerHolder`` on a branch, so it is likely to be accurate. | ||
| 1025 | -In the meantime, think of this as a preview. | ||
| 1026 | - | ||
| 1027 | -First, make sure you have done the steps in the 10.6 section. (Note: | ||
| 1028 | -once qpdf 11 comes out, the goal is to not have to migrate to 10.6 | ||
| 1029 | -first, so it is likely that these sections will be combined.) | ||
| 1030 | - | ||
| 1031 | -If you are explicitly choosing to stick with the backward compatible | ||
| 1032 | -``PointerHolder`` for now, you should define | ||
| 1033 | -``POINTERHOLDER_TRANSITION`` to ``0`` to suppress the warning from | ||
| 1034 | -including ``qpdf/PointerHolder.hh``. Be aware that you may eventually | ||
| 1035 | -have to deal with the transition, though the intention is to leave the | ||
| 1036 | -compatibility layer in place for a while. You should rebuild and test | ||
| 1037 | -your code. There may be compiler errors if you have containers of | ||
| 1038 | -``PointerHolder``, but most code should compile without any changes. | ||
| 1039 | -Even if you have errors, use of ``auto`` or ``decltype`` may enable | ||
| 1040 | -you to write code that works with the old and new API without having | ||
| 1041 | -to use conditional compilation. The | ||
| 1042 | -``POINTERHOLDER_IS_SHARED_POINTER`` is defined in qpdf 11 if you | ||
| 1043 | -``#include <qpdf/PointerHolder.hh>``. | ||
| 1044 | - | ||
| 1045 | -If you want to support older versions of qpdf and still transition so | ||
| 1046 | -that the backward-compatible ``PointerHolder`` is not in use, you can | ||
| 1047 | -separate old code and new code by testing with the | 1024 | +Starting in qpdf 11.0.0, including ``<qpdf/PointerHolder.hh>`` defines |
| 1025 | +the symbol ``POINTERHOLDER_IS_SHARED_POINTER``. If you want to support | ||
| 1026 | +older versions of qpdf and still transition so that the | ||
| 1027 | +backward-compatible ``PointerHolder`` is not in use, you can separate | ||
| 1028 | +old code and new code by testing with the | ||
| 1048 | ``POINTERHOLDER_IS_SHARED_POINTER`` preprocessor symbol, as in | 1029 | ``POINTERHOLDER_IS_SHARED_POINTER`` preprocessor symbol, as in |
| 1049 | 1030 | ||
| 1050 | .. code-block:: c++ | 1031 | .. code-block:: c++ |
| 1051 | 1032 | ||
| 1033 | + #include <qpdf/PointerHolder.hh> | ||
| 1052 | #ifdef POINTERHOLDER_IS_SHARED_POINTER | 1034 | #ifdef POINTERHOLDER_IS_SHARED_POINTER |
| 1053 | std::shared_ptr<X> x; | 1035 | std::shared_ptr<X> x; |
| 1054 | #else | 1036 | #else |
| @@ -1060,6 +1042,7 @@ or | @@ -1060,6 +1042,7 @@ or | ||
| 1060 | 1042 | ||
| 1061 | .. code-block:: c++ | 1043 | .. code-block:: c++ |
| 1062 | 1044 | ||
| 1045 | + #include <qpdf/PointerHolder.hh> | ||
| 1063 | #ifdef POINTERHOLDER_IS_SHARED_POINTER | 1046 | #ifdef POINTERHOLDER_IS_SHARED_POINTER |
| 1064 | auto x_p = std::make_shared<X>(); | 1047 | auto x_p = std::make_shared<X>(); |
| 1065 | X* x = x_p.get(); | 1048 | X* x = x_p.get(); |
| @@ -1074,13 +1057,23 @@ If you don't need to support older versions of qpdf, you can proceed | @@ -1074,13 +1057,23 @@ If you don't need to support older versions of qpdf, you can proceed | ||
| 1074 | with these steps without protecting changes with the preprocessor | 1057 | with these steps without protecting changes with the preprocessor |
| 1075 | symbol. Here are the remaining changes. | 1058 | symbol. Here are the remaining changes. |
| 1076 | 1059 | ||
| 1077 | -- Make sure you have a clean build with ``POINTERHOLDER_TRANSITION`` | ||
| 1078 | - set to ``2``. This means that you are using ``PointerHolder`` in a | ||
| 1079 | - manner that is API-compatible with ``std::shared_ptr`` in all cases | ||
| 1080 | - except for array pointers. | 1060 | +- ``#define POINTERHOLDER_TRANSITION 2`` to enable deprecation of |
| 1061 | + ``getPointer()`` and ``getRefcount()`` | ||
| 1062 | + | ||
| 1063 | +- Replace ``getPointer()`` with ``get()`` and ``getRefcount()`` with | ||
| 1064 | + ``use_count()``. These methods were not present prior to 10.6.0. | ||
| 1065 | + | ||
| 1066 | +When you have gotten your code to compile cleanly with | ||
| 1067 | +``POINTERHOLDER_TRANSITION=2``, you are well on your way to being | ||
| 1068 | +ready for eliminating ``PointerHolder`` entirely. The code at this | ||
| 1069 | +point will not work with any qpdf version prior to 10.6.0. | ||
| 1070 | + | ||
| 1071 | +To support qpdf 11.0.0 and newer and remove ``PointerHolder`` from | ||
| 1072 | +your code, continue with the following steps: | ||
| 1081 | 1073 | ||
| 1082 | - Replace all occurrences of ``PointerHolder`` with | 1074 | - Replace all occurrences of ``PointerHolder`` with |
| 1083 | - ``std::shared_ptr`` except in ``#include <qpdf/PointerHolder.hh>`` | 1075 | + ``std::shared_ptr`` except in the literal statement ``#include |
| 1076 | + <qpdf/PointerHolder.hh>`` | ||
| 1084 | 1077 | ||
| 1085 | - Replace all occurrences of ``make_pointer_holder`` with | 1078 | - Replace all occurrences of ``make_pointer_holder`` with |
| 1086 | ``std::make_shared`` | 1079 | ``std::make_shared`` |