001/* 002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010 011package gololang; 012 013import java.util.Iterator; 014 015/** 016 * Base class for Golo structure objects. 017 * <p> 018 * This class defines common behavior. Golo structure classes are final subclasses of this one. 019 */ 020public abstract class GoloStruct implements Iterable<Tuple>, Comparable<GoloStruct> { 021 022 /** 023 * The array of member names, initialized in Golo structure classes constructors. 024 */ 025 protected String[] members; 026 027 /** 028 * Constructor that does nothing beyond calling {@code super()}. 029 */ 030 public GoloStruct() { 031 super(); 032 } 033 034 /** 035 * Tells whether the instance is frozen or not. 036 * 037 * @return {@code true} if frozen, {@code false} otherwise. 038 */ 039 public abstract boolean isFrozen(); 040 041 /** 042 * Gets the member names as a tuple of strings. 043 * 044 * @return a tuple of member names. 045 */ 046 public Tuple members() { 047 return Tuple.fromArray(members); 048 } 049 050 /** 051 * Gets the current values, in order of member declaration. 052 * 053 * @return a tuple with the current values. 054 */ 055 public Tuple values() { 056 return Tuple.fromArray(toArray()); 057 } 058 059 /** 060 * Destructuration helper. 061 * 062 * @return a tuple with the current values. 063 */ 064 public Tuple destruct() { 065 return Tuple.fromArray(toArray()); 066 } 067 068 /** 069 * Array conversion. 070 * 071 * @return an array containing the values (in member orders) 072 */ 073 public abstract Object[] toArray(); 074 075 /** 076 * Compares this structure with the specified structure for order. 077 * <p>Returns a negative integer, zero, or a positive integer as this structure is less than, 078 * equal to, or greater than the specified structure. 079 * <p>Two structures are compared by comparing their {@link #values()}, thus the 080 * limitations of {@link gololang.Tuple#compareTo} also apply. 081 * <p>Moreover, two structures are only comparable if they have the same type. For instance, 082 * given 083 * <pre class="lisgin"><code class="lang-golo" data-lang="golo"> 084 * struct StructA = {x, y} 085 * struct StructB = {a, b} 086 * 087 * let aStructA = StructA(1, 2) 088 * let aStructB = StructB(1, 3) 089 * </code></pre> 090 * while {@code aStructA: values() < aStructB: values()} is valid and true since we compare two 091 * 2-tuples, comparing directly the structures {@code aStructA < aStructB} throws a 092 * {@link java.lang.ClassCastException}. 093 * 094 * @param other the structure to be compared 095 * @return a negative integer, zero, or a positive integer as this structure is less than, equal to, or greater than the specified structure 096 * @throws NullPointerException if the specified structure is null 097 * @throws IllegalArgumentException if the structure are of different type, of if the type of the members prevent them from being compared pairwise 098 * @since Golo3.1 099 */ 100 @Override 101 public int compareTo(GoloStruct other) { 102 if (this.equals(other)) { 103 return 0; 104 } 105 if (getClass() != other.getClass()) { 106 throw new IllegalArgumentException(String.format( 107 "%s and %s can't be compared; try to compare their values", this, other)); 108 } 109 return this.values().compareTo(other.values()); 110 } 111 112 /** 113 * Gets a member value by name. 114 * 115 * @param member the member name. 116 * @return the member value. 117 * @throws IllegalArgumentException if there is no such member {@code member}. 118 */ 119 public abstract Object get(String member); 120 121 /** 122 * Sets a member value by name. 123 * 124 * @param member the member name. 125 * @param value the value. 126 * @return this instance. 127 * @throws IllegalArgumentException if there is no such member {@code member}. 128 */ 129 public abstract GoloStruct set(String member, Object value); 130 131 /** 132 * Makes a shallow copy. 133 * 134 * @return a copy of this structure. 135 */ 136 public abstract GoloStruct copy(); 137 138 /** 139 * Makes a shallow frozen copy where any member value modification attempt will fail with an {@link IllegalStateException}. 140 * 141 * @return a copy of this structure. 142 */ 143 public abstract GoloStruct frozenCopy(); 144 145 /** 146 * Provides an iterator over the structure. 147 * <p> 148 * Each value is a 2-elements tuple {@code [member, value]}. 149 * 150 * @return an iterator. 151 */ 152 @Override 153 public Iterator<Tuple> iterator() { 154 return new Iterator<Tuple>() { 155 156 final Iterator<?> memberIterator = members().iterator(); 157 final Iterator<?> valuesIterator = values().iterator(); 158 159 @Override 160 public boolean hasNext() { 161 return memberIterator.hasNext(); 162 } 163 164 @Override 165 public Tuple next() { 166 return new Tuple(memberIterator.next(), valuesIterator.next()); 167 } 168 169 @Override 170 public void remove() { 171 throw new UnsupportedOperationException(); 172 } 173 }; 174 } 175}