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 | 160 | it seems also for classes that are intended to be subclassed across |
| 161 | 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 | 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 | 174 | * Traversal of objects is expensive. It's worth adding some complexity |
| 170 | 175 | to avoid needless traversals of objects. | ... | ... |
TODO
| ... | ... | @@ -5,8 +5,7 @@ Next |
| 5 | 5 | * At next release, hide release-qpdf-10.6.3.0cmake* versions at readthedocs |
| 6 | 6 | |
| 7 | 7 | In order: |
| 8 | -* cmake | |
| 9 | -* PointerHolder -> shared_ptr | |
| 8 | +* cmake -- remaining steps | |
| 10 | 9 | * ABI including --json default is latest |
| 11 | 10 | * json v2 |
| 12 | 11 | |
| ... | ... | @@ -29,9 +28,6 @@ Misc |
| 29 | 28 | --show-encryption could potentially retry with this option if the |
| 30 | 29 | first time doesn't work. Then, with the file open, we can read the |
| 31 | 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 | 31 | * Have a warn in QPDF that passes its variable arguments onto QPDFExc |
| 36 | 32 | so you don't have to do warn(QPDFExc(...)) |
| 37 | 33 | |
| ... | ... | @@ -57,6 +53,7 @@ cmake |
| 57 | 53 | QPDF_DLL are public because QPDF_DLL_LOCAL makes the other things |
| 58 | 54 | private. See https://gcc.gnu.org/wiki/Visibility. Make sure this |
| 59 | 55 | is documented. |
| 56 | + * Update "CODING RULES" in "README-maintainer" - search for QPDF_DLL | |
| 60 | 57 | * Nice to have: |
| 61 | 58 | * Split qpdf.test into multiple tests |
| 62 | 59 | * Rework tests so that nothing is written into the source directory. |
| ... | ... | @@ -500,103 +497,6 @@ Other notes: |
| 500 | 497 | way that works for the qpdf/qpdf repository as well since they are |
| 501 | 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 | 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 | 53 | this transparently. All memory management details are also handled by |
| 54 | 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 | 61 | ``QPDFObjectHandle::Factory`` as an example. |
| 64 | 62 | |
| 65 | 63 | The top-level qpdf class is ``QPDF``. A ``QPDF`` object represents a PDF |
| ... | ... | @@ -68,13 +66,14 @@ files. |
| 68 | 66 | |
| 69 | 67 | The primary class for interacting with PDF objects is |
| 70 | 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 | 77 | resolved via a call to the referenced ``QPDF`` instance. This makes it |
| 79 | 78 | essentially impossible to make coding errors in which certain things |
| 80 | 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 | 247 | |
| 249 | 248 | The ``QPDF::resolve()`` method, which is used to resolve an indirect |
| 250 | 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 | 263 | If the requested object is inside of an object stream, the object stream |
| 264 | 264 | itself is first read into memory. Then the tokenizer reads objects from |
| ... | ... | @@ -762,40 +762,47 @@ Smart Pointers |
| 762 | 762 | -------------- |
| 763 | 763 | |
| 764 | 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 | 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 | 771 | removed from qpdf entirely, but this will not happen for a while to |
| 772 | 772 | make it easier for people who need to support multiple versions of |
| 773 | 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 | 807 | - A new global helper function ``make_pointer_holder`` behaves |
| 801 | 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 | 814 | counterpart to the newly added ``QUtil::make_shared_array`` method, |
| 808 | 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 | 818 | PointerHolder<T>`` would only provide a ``T const*`` with its |
| 812 | 819 | ``getPointer`` method. This is incorrect and is not how standard |
| 813 | 820 | library C++ smart pointers or regular pointers behave. The correct |
| ... | ... | @@ -873,16 +880,23 @@ preprocessor symbol or other C++ coding techniques. |
| 873 | 880 | pointer. It also has the seldom-used ``getRefcount()`` method to get |
| 874 | 881 | the reference count. ``std::shared_ptr<T>`` has ``get()`` and |
| 875 | 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 | 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 | 901 | There are two significant things you can do to minimize the impact of |
| 888 | 902 | switching from ``PointerHolder`` to ``std::shared_ptr``: |
| ... | ... | @@ -908,31 +922,35 @@ without consulting this manual. |
| 908 | 922 | - meaning |
| 909 | 923 | |
| 910 | 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 | 927 | - - ``0`` |
| 914 | 928 | - Provide a backward compatible ``PointerHolder`` and suppress |
| 915 | - all deprecation warnings | |
| 929 | + all deprecation warnings; supports all prior qpdf versions | |
| 916 | 930 | |
| 917 | 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 | 935 | - - ``2`` |
| 921 | - - Deprecate ``getPointer()`` and ``getRefcount()`` | |
| 936 | + - Deprecate ``getPointer()`` and ``getRefcount()``; requires | |
| 937 | + qpdf 10.6.0 or later. | |
| 922 | 938 | |
| 923 | 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 | 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 | 949 | Based on the above, here is a procedure for preparing your code. This |
| 932 | 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 | 955 | - Find all occurrences of ``PointerHolder`` in the code. See whether |
| 938 | 956 | any of them can just be outright replaced with ``std::shared_ptr`` |
| ... | ... | @@ -974,8 +992,9 @@ do these steps: |
| 974 | 992 | auto p = std::unique_ptr<X[]>(new X[n]); |
| 975 | 993 | |
| 976 | 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 | 998 | need to be recompiled. |
| 980 | 999 | |
| 981 | 1000 | - ``#define POINTERHOLDER_TRANSITION 1`` to enable deprecation |
| ... | ... | @@ -1000,55 +1019,18 @@ do these steps: |
| 1000 | 1019 | Other examples appear above. |
| 1001 | 1020 | |
| 1002 | 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 | 1029 | ``POINTERHOLDER_IS_SHARED_POINTER`` preprocessor symbol, as in |
| 1049 | 1030 | |
| 1050 | 1031 | .. code-block:: c++ |
| 1051 | 1032 | |
| 1033 | + #include <qpdf/PointerHolder.hh> | |
| 1052 | 1034 | #ifdef POINTERHOLDER_IS_SHARED_POINTER |
| 1053 | 1035 | std::shared_ptr<X> x; |
| 1054 | 1036 | #else |
| ... | ... | @@ -1060,6 +1042,7 @@ or |
| 1060 | 1042 | |
| 1061 | 1043 | .. code-block:: c++ |
| 1062 | 1044 | |
| 1045 | + #include <qpdf/PointerHolder.hh> | |
| 1063 | 1046 | #ifdef POINTERHOLDER_IS_SHARED_POINTER |
| 1064 | 1047 | auto x_p = std::make_shared<X>(); |
| 1065 | 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 | 1057 | with these steps without protecting changes with the preprocessor |
| 1075 | 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 | 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 | 1078 | - Replace all occurrences of ``make_pointer_holder`` with |
| 1086 | 1079 | ``std::make_shared`` | ... | ... |