% Copyright (C) 2018-2019 Olivier Boudeville % % This file is part of the Ceylan-Myriad library. % % This library is free software: you can redistribute it and/or modify % it under the terms of the GNU Lesser General Public License or % the GNU General Public License, as they are published by the Free Software % Foundation, either version 3 of these Licenses, or (at your option) % any later version. % You can also redistribute it and/or modify it under the terms of the % Mozilla Public License, version 1.1 or later. % % This library is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU Lesser General Public License and the GNU General Public License % for more details. % % You should have received a copy of the GNU Lesser General Public % License, of the GNU General Public License and of the Mozilla Public License % along with this library. % If not, see and % . % % Author: Olivier Boudeville [olivier (dot) boudeville (at) esperide (dot) com] % Creation date: Monday, April 30, 2018 % Process dictionary-related support. % % While using the process dictionary is usually regarded with contempt for good % reasons (impure, prone to unwanted side-effects), there are a few specific % cases (ex: the state of a user interfaces being made implicit) where it might % be nevertheless useful. % % We provide basic encapsulation of the ways of interacting with the process % dictionary, notably so that it is easier to locate (ex: thanks to 'grep') the % places where the process dictionary is used. % % This module could have been need 'impure_table' as well, and could have obeyed % a table-like APIaplying only to a singleton. % % Note: associating to a key the 'undefined' value is, here, semantically the % same as not defining such an entry. % -module(process_dictionary). % Actually any term: -type key() :: hashtable:key(). -type value() :: hashtable:value(). -type entry() :: hashtable:entry(). -type entries() :: [ entry() ]. -type entry_count() :: basic_utils:count(). % Explicit form thereof, as a term: -type process_dictionary() :: list_table:list_table(). -export_type([ key/0, value/0, entry/0, entries/0, entry_count/0, process_dictionary/0 ]). -export([ put/2, putAsNew/2, get/1, getExisting/1, remove/1, removeExisting/1, get_dictionary/0, get_keys/0, get_keys_for/1, blank/0, to_string/0 ]). % Puts specified entry in the process dictionary; returns any value that was % previously associated to that key. % -spec put( key(), value() ) -> maybe( value() ). put( Key, Value ) -> erlang:put( Key, Value ). % Puts specified entry in the process dictionary; raises an exception if ever % the specified key was already registered in the process dictionary. % -spec putAsNew( key(), value() ) -> void(). putAsNew( Key, Value ) -> case erlang:get( Key ) of undefined -> erlang:put( Key, Value ); Other -> throw( { already_registered_key, Key, Other } ) end. % Returns the value (if any) associated to the specified key in the process % dictionary. % -spec get( key() ) -> maybe( value() ). get( Key ) -> %trace_utils:debug_fmt( "Getting key '~s' (as ~p).", [ Key, self() ] ), erlang:get( Key ). % Returns the value expected to be associated to the specified key in the % process dictionary, otherwise throws an exception. % -spec getExisting( key() ) -> value(). getExisting( Key ) -> case erlang:get( Key ) of undefined -> throw( { non_registered_key, Key } ); Other -> Other end. % Removes any entry in the process dictionary corresponding to specified key, % returning any value that was associated with it. % -spec remove( key() ) -> maybe( value() ). remove( Key ) -> erlang:erase( Key ). % Removes the entry in the process dictionary expected to correspond to the % specified key and returning it, otherwise throwing an exception, should no % value be associated to specified key. % -spec removeExisting( key() ) -> value(). removeExisting( Key ) -> case erlang:erase( Key ) of undefined -> throw( { non_registered_key, Key } ); Other -> Other end. % Returns the full process dictionary, as a list of {Key,Value} pairs. -spec get_dictionary() -> process_dictionary(). get_dictionary() -> erlang:get(). % Returns a list of all keys present in the process dictionary. -spec get_keys() -> [ key() ]. get_keys() -> erlang:get_keys(). % Returns a list of keys that are associated with the specified value in the % process dictionary. % -spec get_keys_for( value() ) -> [ key() ]. get_keys_for( Value ) -> erlang:get_keys( Value ). % Blanks the process dictionary (erases all entries), and returns its past % content (as a term). % -spec blank() -> process_dictionary(). blank() -> erlang:erase(). % Returns a textual description of the current state of the process dictionary. -spec to_string() -> text_utils:ustring(). to_string() -> case erlang:get() of [] -> text_utils:format( "the process dictionary of ~p is empty", [ self() ] ); Pairs -> Strings = lists:sort( [ text_utils:format( "key '~s' associated to value '~p'", [ K, V ] ) || { K, V } <- Pairs ] ), text_utils:format( "the process dictionary of ~p contains " "~B pair(s): ~s", [ self(), length( Pairs ), text_utils:strings_to_string( Strings ) ] ) end.