{"action":"created","comment":{"url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/comments/36505683","id":36505683,"diff_hunk":"@@ -477,4 +575,262 @@ function TValuedSyntaxNode.Clone: TSyntaxNode;\n   TValuedSyntaxNode(Result).Value := Self.Value;\n end;\n \n+function TValuedSyntaxNode.GetValue : string;\n+begin\n+  Result := TStringCache.Instance.Get(FValue);\n+end;\n+\n+procedure TValuedSyntaxNode.SetValue(AValue : string);\n+begin\n+  FValue := TStringCache.Instance.Add(AValue);\n+end;\n+\n+{ TStringCache.TStringRecValueEqualityComparer }\n+\n+constructor TStringCache.TStringRecValueEqualityComparer.Create;\n+begin\n+  inherited Create();\n+  FStringComparer := TEqualityComparer<string>.Default;\n+end;\n+\n+function TStringCache.TStringRecValueEqualityComparer.Equals(const Left,\n+  Right: TStringRec): Boolean;\n+begin\n+  // Compare by the string it holds only\n+  Result := FStringComparer.Equals(Left.Value, Right.Value);\n+end;\n+\n+function TStringCache.TStringRecValueEqualityComparer.GetHashCode(\n+  const Value: TStringRec): Integer;\n+begin\n+  // Compare by the string it holds only\n+  Result := FStringComparer.GetHashCode(Value.Value);\n+end;\n+\n+{ TStringCache.TStringRecUsageComparer }\n+\n+function TStringCache.TStringRecUsageComparer.Compare(const Left,\n+  Right: TStringRec): Integer;\n+begin\n+  if Left.UsageCount < Right.UsageCount then\n+    Exit(LessThanValue)\n+  else if Left.UsageCount > Right.UsageCount then\n+    Exit(GreaterThanValue)\n+  else // Usage is the same, sort by string\n+    Exit(TComparer<string>.Default.Compare(Left.Value, Right.Value));\n+end;\n+\n+{ TStringCache }\n+\n+class constructor TStringCache.ClassCreate;\n+begin\n+  FInstance := TStringCache.Create;\n+end;\n+\n+class destructor TStringCache.ClassDestroy;\n+begin\n+  FInstance.Free;\n+end;\n+\n+constructor TStringCache.Create;\n+begin\n+  inherited;\n+  FRefCount := 0;\n+  FIsPersistent := false; // Clear the cache when no longer needed\n+  FStringToId := TDictionary<TStringRec, NativeUInt>.Create(\n+    TStringCache.TStringRecValueEqualityComparer.Create);\n+  FIdToString := TList<TStringRec>.Create;\n+\n+  Add(''); // Empty string is always item 0\n+end;\n+\n+destructor TStringCache.Destroy;\n+begin\n+  assert(FRefCount = 0, 'String cache destroyed with live objects still relying on it');\n+  Clear;\n+  FStringToId.Free;\n+  FIdToString.Free;\n+  inherited;\n+end;\n+\n+function TStringCache.Add(const Value: string): NativeUInt;\n+var\n+  Item : TStringRec;\n+begin\n+  Result := 0;\n+  Item := TStringRec.Create(Value);","path":"Source/DelphiAST.Classes.pas","position":263,"original_position":263,"commit_id":"0b6281fcb10c75fec34132f20b9727808c3f119f","original_commit_id":"0b6281fcb10c75fec34132f20b9727808c3f119f","user":{"login":"RomanYankovsky","id":1485472,"avatar_url":"https://avatars.githubusercontent.com/u/1485472?v=3","gravatar_id":"","url":"https://api.github.com/users/RomanYankovsky","html_url":"https://github.com/RomanYankovsky","followers_url":"https://api.github.com/users/RomanYankovsky/followers","following_url":"https://api.github.com/users/RomanYankovsky/following{/other_user}","gists_url":"https://api.github.com/users/RomanYankovsky/gists{/gist_id}","starred_url":"https://api.github.com/users/RomanYankovsky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RomanYankovsky/subscriptions","organizations_url":"https://api.github.com/users/RomanYankovsky/orgs","repos_url":"https://api.github.com/users/RomanYankovsky/repos","events_url":"https://api.github.com/users/RomanYankovsky/events{/privacy}","received_events_url":"https://api.github.com/users/RomanYankovsky/received_events","type":"User","site_admin":false},"body":"Is it possible to make it work without creating an object _before_ we make sure that a string does not exist? This would make it faster.","created_at":"2015-08-07T09:56:49Z","updated_at":"2015-08-07T09:56:49Z","html_url":"https://github.com/RomanYankovsky/DelphiAST/pull/114#discussion_r36505683","pull_request_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/114","_links":{"self":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/comments/36505683"},"html":{"href":"https://github.com/RomanYankovsky/DelphiAST/pull/114#discussion_r36505683"},"pull_request":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/114"}}},"pull_request":{"url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/114","id":41790365,"html_url":"https://github.com/RomanYankovsky/DelphiAST/pull/114","diff_url":"https://github.com/RomanYankovsky/DelphiAST/pull/114.diff","patch_url":"https://github.com/RomanYankovsky/DelphiAST/pull/114.patch","issue_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/issues/114","number":114,"state":"closed","locked":false,"title":"String cache: reduce string memory usage and unique strings used by attributes","user":{"login":"vintagedave","id":8351450,"avatar_url":"https://avatars.githubusercontent.com/u/8351450?v=3","gravatar_id":"","url":"https://api.github.com/users/vintagedave","html_url":"https://github.com/vintagedave","followers_url":"https://api.github.com/users/vintagedave/followers","following_url":"https://api.github.com/users/vintagedave/following{/other_user}","gists_url":"https://api.github.com/users/vintagedave/gists{/gist_id}","starred_url":"https://api.github.com/users/vintagedave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vintagedave/subscriptions","organizations_url":"https://api.github.com/users/vintagedave/orgs","repos_url":"https://api.github.com/users/vintagedave/repos","events_url":"https://api.github.com/users/vintagedave/events{/privacy}","received_events_url":"https://api.github.com/users/vintagedave/received_events","type":"User","site_admin":false},"body":"This is the same as https://github.com/RomanYankovsky/DelphiAST/pull/113 but targeted at the StringsCache branch, not master.","created_at":"2015-08-06T13:58:07Z","updated_at":"2015-08-07T09:56:49Z","closed_at":"2015-08-06T14:22:58Z","merged_at":"2015-08-06T14:22:58Z","merge_commit_sha":"70e17a750c31deb7ea542da0d14dd3af04ec9e28","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/114/commits","review_comments_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/114/comments","review_comment_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/comments{/number}","comments_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/issues/114/comments","statuses_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/statuses/0b6281fcb10c75fec34132f20b9727808c3f119f","head":{"label":"vintagedave:AttributeStringCache","ref":"AttributeStringCache","sha":"0b6281fcb10c75fec34132f20b9727808c3f119f","user":{"login":"vintagedave","id":8351450,"avatar_url":"https://avatars.githubusercontent.com/u/8351450?v=3","gravatar_id":"","url":"https://api.github.com/users/vintagedave","html_url":"https://github.com/vintagedave","followers_url":"https://api.github.com/users/vintagedave/followers","following_url":"https://api.github.com/users/vintagedave/following{/other_user}","gists_url":"https://api.github.com/users/vintagedave/gists{/gist_id}","starred_url":"https://api.github.com/users/vintagedave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vintagedave/subscriptions","organizations_url":"https://api.github.com/users/vintagedave/orgs","repos_url":"https://api.github.com/users/vintagedave/repos","events_url":"https://api.github.com/users/vintagedave/events{/privacy}","received_events_url":"https://api.github.com/users/vintagedave/received_events","type":"User","site_admin":false},"repo":{"id":40182868,"name":"DelphiAST","full_name":"vintagedave/DelphiAST","owner":{"login":"vintagedave","id":8351450,"avatar_url":"https://avatars.githubusercontent.com/u/8351450?v=3","gravatar_id":"","url":"https://api.github.com/users/vintagedave","html_url":"https://github.com/vintagedave","followers_url":"https://api.github.com/users/vintagedave/followers","following_url":"https://api.github.com/users/vintagedave/following{/other_user}","gists_url":"https://api.github.com/users/vintagedave/gists{/gist_id}","starred_url":"https://api.github.com/users/vintagedave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vintagedave/subscriptions","organizations_url":"https://api.github.com/users/vintagedave/orgs","repos_url":"https://api.github.com/users/vintagedave/repos","events_url":"https://api.github.com/users/vintagedave/events{/privacy}","received_events_url":"https://api.github.com/users/vintagedave/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/vintagedave/DelphiAST","description":"Abstract syntax tree builder for Delphi","fork":true,"url":"https://api.github.com/repos/vintagedave/DelphiAST","forks_url":"https://api.github.com/repos/vintagedave/DelphiAST/forks","keys_url":"https://api.github.com/repos/vintagedave/DelphiAST/keys{/key_id}","collaborators_url":"https://api.github.com/repos/vintagedave/DelphiAST/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/vintagedave/DelphiAST/teams","hooks_url":"https://api.github.com/repos/vintagedave/DelphiAST/hooks","issue_events_url":"https://api.github.com/repos/vintagedave/DelphiAST/issues/events{/number}","events_url":"https://api.github.com/repos/vintagedave/DelphiAST/events","assignees_url":"https://api.github.com/repos/vintagedave/DelphiAST/assignees{/user}","branches_url":"https://api.github.com/repos/vintagedave/DelphiAST/branches{/branch}","tags_url":"https://api.github.com/repos/vintagedave/DelphiAST/tags","blobs_url":"https://api.github.com/repos/vintagedave/DelphiAST/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/vintagedave/DelphiAST/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/vintagedave/DelphiAST/git/refs{/sha}","trees_url":"https://api.github.com/repos/vintagedave/DelphiAST/git/trees{/sha}","statuses_url":"https://api.github.com/repos/vintagedave/DelphiAST/statuses/{sha}","languages_url":"https://api.github.com/repos/vintagedave/DelphiAST/languages","stargazers_url":"https://api.github.com/repos/vintagedave/DelphiAST/stargazers","contributors_url":"https://api.github.com/repos/vintagedave/DelphiAST/contributors","subscribers_url":"https://api.github.com/repos/vintagedave/DelphiAST/subscribers","subscription_url":"https://api.github.com/repos/vintagedave/DelphiAST/subscription","commits_url":"https://api.github.com/repos/vintagedave/DelphiAST/commits{/sha}","git_commits_url":"https://api.github.com/repos/vintagedave/DelphiAST/git/commits{/sha}","comments_url":"https://api.github.com/repos/vintagedave/DelphiAST/comments{/number}","issue_comment_url":"https://api.github.com/repos/vintagedave/DelphiAST/issues/comments{/number}","contents_url":"https://api.github.com/repos/vintagedave/DelphiAST/contents/{+path}","compare_url":"https://api.github.com/repos/vintagedave/DelphiAST/compare/{base}...{head}","merges_url":"https://api.github.com/repos/vintagedave/DelphiAST/merges","archive_url":"https://api.github.com/repos/vintagedave/DelphiAST/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/vintagedave/DelphiAST/downloads","issues_url":"https://api.github.com/repos/vintagedave/DelphiAST/issues{/number}","pulls_url":"https://api.github.com/repos/vintagedave/DelphiAST/pulls{/number}","milestones_url":"https://api.github.com/repos/vintagedave/DelphiAST/milestones{/number}","notifications_url":"https://api.github.com/repos/vintagedave/DelphiAST/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/vintagedave/DelphiAST/labels{/name}","releases_url":"https://api.github.com/repos/vintagedave/DelphiAST/releases{/id}","created_at":"2015-08-04T12:18:02Z","updated_at":"2015-08-04T12:18:03Z","pushed_at":"2015-08-06T16:56:58Z","git_url":"git://github.com/vintagedave/DelphiAST.git","ssh_url":"git@github.com:vintagedave/DelphiAST.git","clone_url":"https://github.com/vintagedave/DelphiAST.git","svn_url":"https://github.com/vintagedave/DelphiAST","homepage":"","size":3559,"stargazers_count":0,"watchers_count":0,"language":"Pascal","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"RomanYankovsky:StringsCache","ref":"StringsCache","sha":"e942e141c555fd14d49feb3c219edc1754b8b2de","user":{"login":"RomanYankovsky","id":1485472,"avatar_url":"https://avatars.githubusercontent.com/u/1485472?v=3","gravatar_id":"","url":"https://api.github.com/users/RomanYankovsky","html_url":"https://github.com/RomanYankovsky","followers_url":"https://api.github.com/users/RomanYankovsky/followers","following_url":"https://api.github.com/users/RomanYankovsky/following{/other_user}","gists_url":"https://api.github.com/users/RomanYankovsky/gists{/gist_id}","starred_url":"https://api.github.com/users/RomanYankovsky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RomanYankovsky/subscriptions","organizations_url":"https://api.github.com/users/RomanYankovsky/orgs","repos_url":"https://api.github.com/users/RomanYankovsky/repos","events_url":"https://api.github.com/users/RomanYankovsky/events{/privacy}","received_events_url":"https://api.github.com/users/RomanYankovsky/received_events","type":"User","site_admin":false},"repo":{"id":24018393,"name":"DelphiAST","full_name":"RomanYankovsky/DelphiAST","owner":{"login":"RomanYankovsky","id":1485472,"avatar_url":"https://avatars.githubusercontent.com/u/1485472?v=3","gravatar_id":"","url":"https://api.github.com/users/RomanYankovsky","html_url":"https://github.com/RomanYankovsky","followers_url":"https://api.github.com/users/RomanYankovsky/followers","following_url":"https://api.github.com/users/RomanYankovsky/following{/other_user}","gists_url":"https://api.github.com/users/RomanYankovsky/gists{/gist_id}","starred_url":"https://api.github.com/users/RomanYankovsky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RomanYankovsky/subscriptions","organizations_url":"https://api.github.com/users/RomanYankovsky/orgs","repos_url":"https://api.github.com/users/RomanYankovsky/repos","events_url":"https://api.github.com/users/RomanYankovsky/events{/privacy}","received_events_url":"https://api.github.com/users/RomanYankovsky/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/RomanYankovsky/DelphiAST","description":"Abstract syntax tree builder for Delphi","fork":false,"url":"https://api.github.com/repos/RomanYankovsky/DelphiAST","forks_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/forks","keys_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/keys{/key_id}","collaborators_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/teams","hooks_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/hooks","issue_events_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/issues/events{/number}","events_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/events","assignees_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/assignees{/user}","branches_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/branches{/branch}","tags_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/tags","blobs_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/git/refs{/sha}","trees_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/git/trees{/sha}","statuses_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/statuses/{sha}","languages_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/languages","stargazers_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/stargazers","contributors_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/contributors","subscribers_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/subscribers","subscription_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/subscription","commits_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/commits{/sha}","git_commits_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/git/commits{/sha}","comments_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/comments{/number}","issue_comment_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/issues/comments{/number}","contents_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/contents/{+path}","compare_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/compare/{base}...{head}","merges_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/merges","archive_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/downloads","issues_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/issues{/number}","pulls_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls{/number}","milestones_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/milestones{/number}","notifications_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/labels{/name}","releases_url":"https://api.github.com/repos/RomanYankovsky/DelphiAST/releases{/id}","created_at":"2014-09-14T09:35:31Z","updated_at":"2015-08-04T18:26:25Z","pushed_at":"2015-08-06T16:56:59Z","git_url":"git://github.com/RomanYankovsky/DelphiAST.git","ssh_url":"git@github.com:RomanYankovsky/DelphiAST.git","clone_url":"https://github.com/RomanYankovsky/DelphiAST.git","svn_url":"https://github.com/RomanYankovsky/DelphiAST","homepage":"","size":3559,"stargazers_count":43,"watchers_count":43,"language":"Pascal","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":21,"mirror_url":null,"open_issues_count":21,"forks":21,"open_issues":21,"watchers":43,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/114"},"html":{"href":"https://github.com/RomanYankovsky/DelphiAST/pull/114"},"issue":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/issues/114"},"comments":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/issues/114/comments"},"review_comments":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/114/comments"},"review_comment":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/pulls/114/commits"},"statuses":{"href":"https://api.github.com/repos/RomanYankovsky/DelphiAST/statuses/0b6281fcb10c75fec34132f20b9727808c3f119f"}}}}