diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql
index ee2f3c95a..42b92757c 100644
--- a/docs/docset/docSet.sql
+++ b/docs/docset/docSet.sql
@@ -131,6 +131,8 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::~basic_json', 'Me
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document', 'Class', 'api/basic_json_document/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::basic_json_document', 'Constructor', 'api/basic_json_document/basic_json_document/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::accept', 'Function', 'api/basic_json_document/accept/index.html');
+INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::erase', 'Method', 'api/basic_json_document/erase/index.html');
+INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::insert', 'Method', 'api/basic_json_document/insert/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::is_discarded', 'Method', 'api/basic_json_document/is_discarded/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::memory_usage', 'Method', 'api/basic_json_document/memory_usage/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::node_count', 'Method', 'api/basic_json_document/node_count/index.html');
diff --git a/docs/mkdocs/docs/api/basic_json_document/erase.md b/docs/mkdocs/docs/api/basic_json_document/erase.md
new file mode 100644
index 000000000..cbdc79765
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_document/erase.md
@@ -0,0 +1,128 @@
+# nlohmann::basic_json_document::erase
+
+```cpp
+// (1)
+std::size_t erase(view_type object, string_view_t key);
+
+// (2)
+template
+void erase(view_type array, I idx);
+
+// (3)
+std::size_t erase(const json_pointer& ptr);
+```
+
+Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
+has `erase`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
+
+1. Removes every member of `object` whose key is `key` (see [Notes](#notes) on duplicate keys) and returns how many
+ were removed; `#!cpp 0` if `object` has no member with this key.
+2. Removes the element at index `idx` of `array`, which must already exist (`#!cpp idx < array.size()`).
+3. Removes the value the JSON pointer `ptr` refers to, relative to [`root()`](root.md), and returns how many values
+ were removed: the *parent* of the target must already exist, and the target itself is removed as in 1. (an object
+ member; `#!cpp 0` or more) or 2. (an array element; always `#!cpp 1`). `ptr` must not be empty -- [`root()`](root.md)
+ itself cannot be erased.
+
+## Template parameters
+
+`I`
+: an integral type other than `#!cpp bool`, deduced (overloads taking a `#!cpp bool` or a non-integral type for
+ `idx` do not participate in overload resolution).
+
+## Parameters
+
+`object` (in)
+: the object to remove a member of
+
+`array` (in)
+: the array to remove an element of
+
+`key` (in)
+: the key of the member(s) to remove
+
+`idx` (in)
+: the index of the element to remove; a negative value throws (see [Exceptions](#exceptions))
+
+`ptr` (in)
+: a JSON pointer to the value to remove, relative to `root()`
+
+## Return value
+
+1. the number of removed members (`#!cpp 0` if `object` had none with this `key`)
+2. (nothing)
+3. the number of removed values (`#!cpp 0` or more for an object member, always `#!cpp 1` for an array element)
+
+## Exceptions
+
+1. Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) if `object` is not an object -- the
+ same message [`BasicJsonType::erase`](../basic_json/erase.md) throws for the same type.
+2. Throws `type_error.307` if `array` is not an array. Throws
+ [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `idx` is negative, or if
+ `#!cpp idx >= array.size()`.
+3. Throws [`out_of_range.405`](../../home/exceptions.md#jsonexceptionout_of_range405) ("JSON pointer has no parent")
+ if `ptr` is empty. Throws what [`at`](../basic_json_view/at.md) throws (overload 3) for resolving `ptr`'s parent.
+ For the last reference token itself: if the parent is an array, throws what 2. throws for an index that is out of
+ range, or, for a token that is not a valid array index,
+ [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) (a leading `#!cpp '0'`),
+ [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) (not a number),
+ [`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) (too large for `size_type`), or
+ [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) (an empty token); otherwise (an
+ object, or a primitive value the pointer's parent resolves to) throws what 1. throws.
+
+Every overload also throws [`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view
+does not belong to this document") if `object`/`array` is a [discarded](../basic_json_view/is_discarded.md) view or a
+view of a *different* document (overloads 1-2 only; overload 3 always starts from this document's own
+[`root()`](root.md)).
+
+## Complexity
+
+1. Linear in the number of members of `object`.
+2. Linear in the number of elements of `array` at or after `idx` (they move one slot over).
+3. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
+ that level or the index into the array (as [`at`](../basic_json_view/at.md)), plus the complexity of 1. or 2. for
+ the last token.
+
+## Notes
+
+!!! info "Duplicate keys"
+
+ Overload 1. removes *every* member with `key`, not just the first -- unlike [`set`](set.md), which assigns the
+ first occurrence and drops the rest. This is why it returns a count rather than a single view: there may be
+ more than one member removed, or none.
+
+Like [`set`](set.md) and [`push_back`](push_back.md), `erase` never moves an element's *value*: a view still
+referring to a removed member or element keeps showing what it last held (see [Edits](index.md#edits)) -- it just no
+longer appears when `array`/`object` is read, dumped, or iterated. Removing an element of `array` (2.) does shift the
+*links* to the elements after it, the same way `insert`, `set`, or `push_back` on the same array would; any iterator
+already taken over `array`/`object` is invalidated by an erase, since it was walking the old layout.
+
+## Examples
+
+??? example
+
+ The example below drops a deprecated field and a decommissioned entry from a configuration document -- using all
+ three overloads -- and shows what stays intact that would not with a plain `json`/`ordered_json` value: the order
+ of the fields around the ones removed, and the exact spelling of a number that was never touched.
+
+ ```cpp
+ --8<-- "examples/basic_json_document__erase.cpp"
+ ```
+
+ Output:
+
+ ```json
+ --8<-- "examples/basic_json_document__erase.output"
+ ```
+
+## See also
+
+- [insert](insert.md) - insert an element into an array
+- [set](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers to
+- [push_back](push_back.md) - append to an array
+- [root](root.md) - the view of the root value, the starting point of overload 3
+- [`BasicJsonType::erase`](../basic_json/erase.md) - the corresponding function of `basic_json`
+- [Edits](index.md#edits) - what an edit guarantees, for every overload
+
+## Version history
+
+- Added in version 3.13.0.
diff --git a/docs/mkdocs/docs/api/basic_json_document/index.md b/docs/mkdocs/docs/api/basic_json_document/index.md
index a5ffbe73a..534b63755 100644
--- a/docs/mkdocs/docs/api/basic_json_document/index.md
+++ b/docs/mkdocs/docs/api/basic_json_document/index.md
@@ -19,10 +19,10 @@ it (a copy, or an rvalue `#!cpp std::string` that was moved in); see [`owns_sour
is move-only: copying a document would either duplicate a potentially large index and text, or leave two documents
claiming to borrow the same buffer, so it is disabled.
-With `#!cpp Editable == true`, the document also offers [`set`](set.md) and [`push_back`](push_back.md) to change
-values in place, see [Edits](#edits) below. The source text itself is never written; a read-only document
-(`#!cpp Editable == false`, the default) does not carry any of the bookkeeping edits need, and calling `set` or
-`push_back` on one fails to compile (`#!cpp static_assert`).
+With `#!cpp Editable == true`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
+[`insert`](insert.md), and [`erase`](erase.md) to change values in place, see [Edits](#edits) below. The source text
+itself is never written; a read-only document (`#!cpp Editable == false`, the default) does not carry any of the
+bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp static_assert`).
## Template parameters
@@ -32,8 +32,8 @@ values in place, see [Edits](#edits) below. The source text itself is never writ
is checked with a `static_assert`.
`Editable`
-: whether the document supports [`set`](set.md) and [`push_back`](push_back.md) (optional, `#!cpp false` by
- default). See [Edits](#edits) below.
+: whether the document supports [`set`](set.md), [`push_back`](push_back.md), [`insert`](insert.md), and
+ [`erase`](erase.md) (optional, `#!cpp false` by default). See [Edits](#edits) below.
## Specializations
@@ -66,11 +66,15 @@ values in place, see [Edits](#edits) below. The source text itself is never writ
- [**set**](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers
to (`#!cpp Editable` documents only)
- [**push_back**](push_back.md) - append to an array (`#!cpp Editable` documents only)
+- [**insert**](insert.md) - insert an element into an array before a given position (`#!cpp Editable` documents only)
+- [**erase**](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
+ (`#!cpp Editable` documents only)
## Edits
-An editable document (`#!cpp Editable == true`) can be changed after parsing, with [`set`](set.md) and
-[`push_back`](push_back.md); [`json_editable_document`](../json_editable_document.md) and
+An editable document (`#!cpp Editable == true`) can be changed after parsing, with [`set`](set.md),
+[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md);
+[`json_editable_document`](../json_editable_document.md) and
[`ordered_json_editable_document`](../ordered_json_editable_document.md) are the corresponding specializations. A few
points apply to every edit:
diff --git a/docs/mkdocs/docs/api/basic_json_document/insert.md b/docs/mkdocs/docs/api/basic_json_document/insert.md
new file mode 100644
index 000000000..b513dfc0d
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_document/insert.md
@@ -0,0 +1,114 @@
+# nlohmann::basic_json_document::insert
+
+```cpp
+template
+view_type insert(view_type array, I idx, V&& value);
+```
+
+Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
+has `insert`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
+
+Inserts `value` into `array` as a new element before position `idx`, which must not be past the end
+(`#!cpp idx <= array.size()`; `#!cpp idx == array.size()` appends, like [`push_back`](push_back.md)). Unlike
+[`push_back`](push_back.md), a [null](../basic_json_view/is_null.md) `array` does *not* first become an empty array:
+`array` must already be an array.
+
+`value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any* document -- read-only or
+editable, and it does not have to be `array`'s own document -- which is copied so that nothing is shared with the
+source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
+strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
+
+## Template parameters
+
+`I`
+: an integral type other than `#!cpp bool`, deduced (overloads taking a `#!cpp bool` or a non-integral type for
+ `idx` do not participate in overload resolution).
+
+`V`
+: the type of `value`, deduced; see above for what is accepted.
+
+## Parameters
+
+`array` (in)
+: the array to insert into
+
+`idx` (in)
+: the position to insert `value` before; a negative value throws (see [Exceptions](#exceptions))
+
+`value` (in)
+: the value to insert
+
+## Return value
+
+a view of the new element, now holding `value`
+
+## Exception safety
+
+Basic exception safety: `value` is fully encoded -- including the checks below -- into storage owned by the document
+before anything already reachable from [`root()`](root.md) is touched, so a failure while encoding `value` (an
+invalid argument, or `#!cpp std::bad_alloc`) leaves the document completely unchanged, other than memory allocated
+for the encoding that is not reclaimed. A failure of a later allocation -- while `array` switches from its parsed
+layout to a growable block, or while that block grows, see [Notes](#notes) -- can still leave `array` already
+switched to that layout even though `value` itself was not inserted.
+
+## Exceptions
+
+Throws [`type_error.309`](../../home/exceptions.md#jsonexceptiontype_error309) if `array` is not an array -- the same
+message [`BasicJsonType::insert`](../basic_json/insert.md) throws for the same type; a null `array` throws this too
+(see above). Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `idx` is negative,
+or if `#!cpp idx > array.size()`. Throws
+[`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view does not belong to this
+document") if `array` is a [discarded](../basic_json_view/is_discarded.md) view or a view of a *different* document.
+Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `value` is a
+[discarded](../basic_json_view/is_discarded.md) view or a [discarded](../basic_json/is_discarded.md) `BasicJsonType`
+value, and [`type_error.319`](../../home/exceptions.md#jsonexceptiontype_error319) if `value` is (or contains) a
+binary value -- `BasicJsonType` can hold one, but a `json_document` cannot. Throws
+[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if `value` is (or contains) a string that is
+not valid UTF-8, with the same message [`BasicJsonType::dump()`](../basic_json/dump.md) gives for that string.
+
+## Complexity
+
+Linear in the number of elements of `array` at or after `idx` (they move one slot over), plus time linear in the
+size of `value` to encode it into the document's storage (constant for a scalar, linear in the number of nested
+values for an array or object): like [`push_back`](push_back.md), the elements of `array` move to a growable block
+of links the first time it is inserted into (or [`set`](set.md)/[`push_back`](push_back.md) on), and that block
+grows in amortized constant time; inserting before the end within that block still shifts every later element.
+
+## Notes
+
+Like [`set`](set.md) on a member or an element, `insert` never moves an existing *element's value* -- only where
+`array`'s *links* to its elements live -- so a view of an existing element of `array` stays valid across an
+`insert`, and keeps referring to the same element even though its index shifts. Any iterator already taken over
+`array` is invalidated, since it was walking the old layout. See [Edits](index.md#edits) for what stays valid across
+an edit in general.
+
+## Examples
+
+??? example
+
+ The example below inserts a step into the middle of a deployment plan, without touching the steps that come
+ after it, and shows that a view taken before the insert keeps referring to the same element even though its
+ index shifts -- something a plain `json`/`ordered_json` array, or its `std::vector`-based storage, has no
+ equivalent for.
+
+ ```cpp
+ --8<-- "examples/basic_json_document__insert.cpp"
+ ```
+
+ Output:
+
+ ```json
+ --8<-- "examples/basic_json_document__insert.output"
+ ```
+
+## See also
+
+- [push_back](push_back.md) - append to an array
+- [erase](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
+- [set](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers to
+- [`BasicJsonType::insert`](../basic_json/insert.md) - the corresponding function of `basic_json`
+- [Edits](index.md#edits) - what an edit guarantees, for every overload
+
+## Version history
+
+- Added in version 3.13.0.
diff --git a/docs/mkdocs/docs/api/basic_json_document/push_back.md b/docs/mkdocs/docs/api/basic_json_document/push_back.md
index b50f6a347..37ce10bc5 100644
--- a/docs/mkdocs/docs/api/basic_json_document/push_back.md
+++ b/docs/mkdocs/docs/api/basic_json_document/push_back.md
@@ -91,6 +91,8 @@ Like [`set`](set.md) on a member or an element, `push_back` never moves an exist
## See also
- [set](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers to
+- [insert](insert.md) - insert an element into an array before a given position
+- [erase](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
- [root](root.md) - the view of the root value
- [`BasicJsonType::push_back`](../basic_json/push_back.md) - the corresponding function of `basic_json`
- [Edits](index.md#edits) - what an edit guarantees, for every overload
diff --git a/docs/mkdocs/docs/api/basic_json_document/set.md b/docs/mkdocs/docs/api/basic_json_document/set.md
index 3741cf44a..f9d73b94c 100644
--- a/docs/mkdocs/docs/api/basic_json_document/set.md
+++ b/docs/mkdocs/docs/api/basic_json_document/set.md
@@ -180,6 +180,8 @@ one-node scalar.
## See also
- [push_back](push_back.md) - append to an array
+- [insert](insert.md) - insert an element into an array
+- [erase](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
- [root](root.md) - the view of the root value, the starting point of overload 4
- [`basic_json_view::dump`](../basic_json_view/dump.md) - serialize the document, keeping an untouched number's
spelling with `#!cpp number_format::source`
diff --git a/docs/mkdocs/docs/examples/basic_json_document__erase.cpp b/docs/mkdocs/docs/examples/basic_json_document__erase.cpp
new file mode 100644
index 000000000..4b3197698
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_document__erase.cpp
@@ -0,0 +1,38 @@
+#include
+#include
+
+using json = nlohmann::json;
+using json_editable_document = nlohmann::json_editable_document;
+using json_editable_view = nlohmann::json_editable_view;
+
+int main()
+{
+ // a deprecated field is dropped from a configuration file, and a
+ // decommissioned replica is removed from the list -- "price" keeps its
+ // trailing zero, and the fields around the removed ones keep their order
+ const std::string text = R"({
+ "name": "cache",
+ "legacy_host": "db0",
+ "host": "db1",
+ "price": 19.90,
+ "replicas": ["db2", "db3", "db4"]
+})";
+
+ json_editable_document doc = json_editable_document::parse(text);
+
+ doc.erase(doc.root(), "legacy_host"); // (1) an object member
+ doc.erase(doc.root()["replicas"], 1); // (2) an array element ("db3")
+ const std::size_t removed = doc.erase(json::json_pointer("/replicas/0")); // (3) via a JSON pointer
+
+ std::cout << removed << '\n';
+ std::cout << doc.root().dump(2, ' ', false, json_editable_view::number_format::source) << "\n\n";
+
+ // the same edits on a plain json value: object_t is a std::map, so
+ // parsing already sorted the keys, and dump() rewrites every number to
+ // its shortest form, even "price", which was never touched
+ json plain = json::parse(text);
+ plain.erase("legacy_host");
+ plain["replicas"].erase(1);
+ plain["replicas"].erase(0);
+ std::cout << plain.dump(2) << '\n';
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_document__erase.output b/docs/mkdocs/docs/examples/basic_json_document__erase.output
new file mode 100644
index 000000000..de764877a
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_document__erase.output
@@ -0,0 +1,18 @@
+1
+{
+ "name": "cache",
+ "host": "db1",
+ "price": 19.90,
+ "replicas": [
+ "db4"
+ ]
+}
+
+{
+ "host": "db1",
+ "name": "cache",
+ "price": 19.9,
+ "replicas": [
+ "db4"
+ ]
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_document__insert.cpp b/docs/mkdocs/docs/examples/basic_json_document__insert.cpp
new file mode 100644
index 000000000..1c04bd6cc
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_document__insert.cpp
@@ -0,0 +1,38 @@
+#include
+#include
+
+using json = nlohmann::json;
+using json_editable_document = nlohmann::json_editable_document;
+using json_editable_view = nlohmann::json_editable_view;
+
+int main()
+{
+ // a deployment plan -- "budget" is written with a trailing zero that has
+ // no effect on its value
+ const std::string text = R"({
+ "release": "2026.09",
+ "steps": ["build", "test", "deploy"],
+ "budget": 19.90
+})";
+
+ json_editable_document doc = json_editable_document::parse(text);
+
+ const std::size_t deploy_index = 2;
+ const auto deploy = doc.root()["steps"][deploy_index]; // held across the insert
+
+ doc.insert(doc.root()["steps"], deploy_index, "smoke-test"); // insert before "deploy"
+
+ // the held view still refers to "deploy", even though its index moved
+ // from 2 to 3, and nothing else in the document was touched
+ std::cout << deploy.dump() << '\n';
+ std::cout << doc.root().dump(2, ' ', false, json_editable_view::number_format::source) << "\n\n";
+
+ // the same edit on a plain json value: an index held from before the
+ // insert now refers to whatever moved into that slot, and dump()
+ // rewrites "budget" to its shortest form even though it was never
+ // touched
+ json plain = json::parse(text);
+ plain["steps"].insert(plain["steps"].begin() + static_cast(deploy_index), "smoke-test");
+ std::cout << plain["steps"][deploy_index].dump() << '\n';
+ std::cout << plain.dump(2) << '\n';
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_document__insert.output b/docs/mkdocs/docs/examples/basic_json_document__insert.output
new file mode 100644
index 000000000..1b2480df1
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_document__insert.output
@@ -0,0 +1,23 @@
+"deploy"
+{
+ "release": "2026.09",
+ "steps": [
+ "build",
+ "test",
+ "smoke-test",
+ "deploy"
+ ],
+ "budget": 19.90
+}
+
+"smoke-test"
+{
+ "budget": 19.9,
+ "release": "2026.09",
+ "steps": [
+ "build",
+ "test",
+ "smoke-test",
+ "deploy"
+ ]
+}
diff --git a/docs/mkdocs/docs/features/json_view.md b/docs/mkdocs/docs/features/json_view.md
index f67fe5160..8a275db4a 100644
--- a/docs/mkdocs/docs/features/json_view.md
+++ b/docs/mkdocs/docs/features/json_view.md
@@ -193,11 +193,13 @@ Everything above is read-only: a `json_document`/`json_view` lets you look at a
not change it. [`basic_json_document`](../api/basic_json_document/index.md) -- more conveniently
spelled [`json_editable_document`](../api/json_editable_document.md) or
[`ordered_json_editable_document`](../api/ordered_json_editable_document.md) -- also lets you
-[`set`](../api/basic_json_document/set.md) a value and [`push_back`](../api/basic_json_document/push_back.md) onto
-an array, still without ever building a `basic_json` tree for parts you do not touch.
+[`set`](../api/basic_json_document/set.md) a value, [`push_back`](../api/basic_json_document/push_back.md) onto or
+[`insert`](../api/basic_json_document/insert.md) into an array, and [`erase`](../api/basic_json_document/erase.md)
+an object member or an array element, still without ever building a `basic_json` tree for parts you do not touch.
`#!cpp Editable` defaults to `#!cpp false`, so `json_document`/`ordered_json_document` are unaffected -- they carry
-none of the bookkeeping edits need, and calling `set`/`push_back` on one is a compile error, not a runtime one.
+none of the bookkeeping edits need, and calling `set`/`push_back`/`insert`/`erase` on one is a compile error, not a
+runtime one.
### Why: editing without reformatting
@@ -212,8 +214,9 @@ or `ordered_json` value in place lossy. Say you parse a configuration file, patc
An editable document keeps both. [`dump()`](../api/basic_json_view/dump.md) of an edited document writes members in
document order -- a member [`set`](../api/basic_json_document/set.md) added goes at the end, exactly where it was
-inserted -- and [`number_format::source`](../api/basic_json_view/number_format.md) keeps the exact spelling of
-every number an edit did not itself touch; a number an edit *did* touch is written the way
+inserted, and an [`erase`](../api/basic_json_document/erase.md)d member simply leaves a gap: everything around it
+keeps its place -- and [`number_format::source`](../api/basic_json_view/number_format.md) keeps the exact spelling
+of every number an edit did not itself touch; a number an edit *did* touch is written the way
[`BasicJsonType::dump()`](../api/basic_json/dump.md) would write it, since there is no source spelling for a brand
new value.
@@ -236,10 +239,11 @@ parsed into for as long as it is not itself replaced. So every [view](../api/bas
an edit, including a previously obtained [`root()`](../api/basic_json_document/root.md), stays valid and, if it
still refers to the edited value, sees the edit; a view of a value a later edit drops or replaces just keeps showing
what it last held. New values go to storage the document allocates and owns on demand. The one thing an edit does
-invalidate is the **iterators** taken over an edited array or object: the first time one of its elements is set or
-appended to, its elements move from the parsed, fixed layout to a growable block of links so that
-[`push_back`](../api/basic_json_document/push_back.md) can later grow it in amortized constant time -- existing
-elements are not touched, but an iterator that was walking the old layout no longer matches. A string obtained with
+invalidate is the **iterators** taken over an edited array or object: the first time one of its elements is set,
+appended to, inserted into, or erased, its elements move from the parsed, fixed layout to a growable block of links
+so that [`push_back`](../api/basic_json_document/push_back.md) can later grow it in amortized constant time --
+existing elements are not touched, but an iterator that was walking the old layout no longer matches. A string
+obtained with
[`get_string()`](../api/basic_json_view/get_string.md) is unaffected either way and stays valid across further
edits. See [`basic_json_document`'s Edits](../api/basic_json_document/index.md#edits) for the details, and
[`set`'s Exception safety](../api/basic_json_document/set.md#exception-safety) for what an edit guarantees if it
@@ -251,7 +255,7 @@ the index is described in the [architecture overview](../home/architecture.md#no
| | [`json`](../api/json.md) / [`ordered_json`](../api/ordered_json.md) | [SAX interface](parsing/sax_interface.md) | [`json_document`](../api/json_document.md) / [`json_view`](../api/json_view.md) | [`json_editable_document`](../api/json_editable_document.md) / [`json_editable_view`](../api/json_editable_view.md) |
|---|---|---|---|---|
| **Ownership** | owns every value | owns nothing; you decide what to keep, in your handler | borrows or owns the *text*; the index is always owned by the document | same as `json_document`; edits go to storage the document owns |
-| **Mutability** | freely mutable | not applicable (a one-shot event stream) | read-only | [`set`](../api/basic_json_document/set.md)/[`push_back`](../api/basic_json_document/push_back.md) edit in place; the source text is never rewritten |
+| **Mutability** | freely mutable | not applicable (a one-shot event stream) | read-only | [`set`](../api/basic_json_document/set.md)/[`push_back`](../api/basic_json_document/push_back.md)/[`insert`](../api/basic_json_document/insert.md)/[`erase`](../api/basic_json_document/erase.md) edit in place; the source text is never rewritten |
| **What you get** | a full tree you can read, write, and keep as long as you like | a sequence of callbacks; whatever your handler builds from them | a flat index plus, on demand, [`materialize()`](../api/basic_json_view/materialize.md)d `json`/`ordered_json` values for the parts you actually use | the same, plus [`dump()`](../api/basic_json_view/dump.md) of an edited document that keeps the member order and, with [`number_format::source`](../api/basic_json_view/number_format.md), the spelling of every untouched number |
| **Typical use** | general-purpose JSON handling: config, request/response bodies you build or modify, anything you hold onto | validating or projecting a text into your own data structure without ever holding the whole thing as JSON | large or high-volume input where you only need part of it, or need it repeatedly, and can keep the source text (or a copy) alive for as long as the document lives | a document you read, patch a few fields of, and write back -- a configuration file, for instance -- where the rest of it should come back exactly as it was |
diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml
index 58c3abf36..462fddb34 100644
--- a/docs/mkdocs/mkdocs.yml
+++ b/docs/mkdocs/mkdocs.yml
@@ -233,6 +233,8 @@ nav:
- 'Overview': api/basic_json_document/index.md
- '(Constructor)': api/basic_json_document/basic_json_document.md
- 'accept': api/basic_json_document/accept.md
+ - 'erase': api/basic_json_document/erase.md
+ - 'insert': api/basic_json_document/insert.md
- 'is_discarded': api/basic_json_document/is_discarded.md
- 'memory_usage': api/basic_json_document/memory_usage.md
- 'node_count': api/basic_json_document/node_count.md