copy_on_write_block.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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. 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. CopyOnWriteBlock(SemIR::File& file, UninitializedBlock uninit)
  31. : file_(file),
  32. source_id_(BlockIdType::Invalid),
  33. id_(file_.inst_blocks().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. // Sets the element at index `i` within the block. Lazily allocates a new
  39. // block when the value changes for the first time.
  40. auto Set(int i, typename BlockIdType::ElementType value) -> void {
  41. if (source_id_.is_valid() && (file_.*ValueStore)().Get(id_)[i] == value) {
  42. return;
  43. }
  44. if (id_ == source_id_) {
  45. id_ = (file_.*ValueStore)().Add((file_.*ValueStore)().Get(source_id_));
  46. }
  47. (file_.*ValueStore)().Get(id_)[i] = value;
  48. }
  49. private:
  50. SemIR::File& file_;
  51. BlockIdType source_id_;
  52. BlockIdType id_ = source_id_;
  53. };
  54. using CopyOnWriteInstBlock = CopyOnWriteBlock<InstBlockId, &File::inst_blocks>;
  55. using CopyOnWriteTypeBlock = CopyOnWriteBlock<TypeBlockId, &File::type_blocks>;
  56. } // namespace Carbon::SemIR
  57. #endif // CARBON_TOOLCHAIN_SEM_IR_COPY_ON_WRITE_BLOCK_H_