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