copy_on_write_block.h 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_SEM_IR_COPY_ON_WRITE_BLOCK_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_COPY_ON_WRITE_BLOCK_H_
  6. #include "toolchain/sem_ir/file.h"
  7. #include "toolchain/sem_ir/ids.h"
  8. namespace Carbon::SemIR {
  9. // A handle to a new block that may be modified, with copy-on-write semantics.
  10. //
  11. // The constructor is given the ID of an existing block that provides the
  12. // initial contents of the new block. The new block is lazily allocated; if no
  13. // modifications have been made, the `id()` function will return the original
  14. // block ID.
  15. //
  16. // This is intended to avoid an unnecessary block allocation in the case where
  17. // the new block ends up being exactly the same as the original block.
  18. template <typename BlockIdType, auto (SemIR::File::*ValueStore)()>
  19. class CopyOnWriteBlock {
  20. public:
  21. struct UninitializedBlock {
  22. size_t size;
  23. };
  24. // Constructs the block. `source_id` is used as the initial value of the
  25. // block.
  26. explicit CopyOnWriteBlock(SemIR::File& file, BlockIdType source_id)
  27. : file_(file), source_id_(source_id) {}
  28. // Constructs the block, treating the original block as an uninitialized block
  29. // with `size` elements.
  30. explicit CopyOnWriteBlock(SemIR::File& file, UninitializedBlock uninit)
  31. : file_(file),
  32. source_id_(BlockIdType::None),
  33. id_((file_.*ValueStore)().AddUninitialized(uninit.size)) {}
  34. // Gets a block ID containing the resulting elements. Note that further
  35. // modifications may or may not allocate a new ID, so this should only be
  36. // called once all modifications have been performed.
  37. auto id() const -> BlockIdType { return id_; }
  38. // Gets a canonical block ID containing the resulting elements. This assumes
  39. // the original block ID, if specified, was also canonical.
  40. auto GetCanonical() const -> BlockIdType {
  41. return id_ == source_id_ ? id_ : (file_.*ValueStore)().MakeCanonical(id_);
  42. }
  43. // Sets the element at index `i` within the block. Lazily allocates a new
  44. // block when the value changes for the first time.
  45. auto Set(int i, typename BlockIdType::ElementType value) -> void {
  46. if (source_id_.has_value() && (file_.*ValueStore)().Get(id_)[i] == value) {
  47. return;
  48. }
  49. if (id_ == source_id_) {
  50. id_ = (file_.*ValueStore)().Add((file_.*ValueStore)().Get(source_id_));
  51. }
  52. (file_.*ValueStore)().GetMutable(id_)[i] = value;
  53. }
  54. private:
  55. SemIR::File& file_;
  56. BlockIdType source_id_;
  57. BlockIdType id_ = source_id_;
  58. };
  59. using CopyOnWriteInstBlock = CopyOnWriteBlock<InstBlockId, &File::inst_blocks>;
  60. using CopyOnWriteStructTypeFieldsBlock =
  61. CopyOnWriteBlock<StructTypeFieldsId, &File::struct_type_fields>;
  62. using CopyOnWriteTypeBlock = CopyOnWriteBlock<TypeBlockId, &File::type_blocks>;
  63. } // namespace Carbon::SemIR
  64. #endif // CARBON_TOOLCHAIN_SEM_IR_COPY_ON_WRITE_BLOCK_H_